diff options
Diffstat (limited to 'backend')
45 files changed, 4464 insertions, 425 deletions
| diff --git a/backend/Makefile.am b/backend/Makefile.am index f84d23e..40ec6c6 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -83,7 +83,7 @@ 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 fujitsu.conf genesys.conf gphoto2.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\  	       leo.conf lexmark.conf ma1509.conf magicolor.conf \ @@ -171,7 +171,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 libfujitsu.la libgenesys.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 \ @@ -204,7 +204,7 @@ 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-fujitsu.la libsane-genesys.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 \ @@ -471,6 +471,19 @@ 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)  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 +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_JPEG_LO@ $(JPEG_LIBS) $(USB_LIBS) $(MATH_LIB) $(RESMGR_LIBS) +EXTRA_DIST += epsonds.conf.in +  libfujitsu_la_SOURCES = fujitsu.c fujitsu.h fujitsu-scsi.h  libfujitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=fujitsu diff --git a/backend/Makefile.in b/backend/Makefile.in index 3f7fa12..b688e93 100644 --- a/backend/Makefile.in +++ b/backend/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am.  # @configure_input@  # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -211,6 +211,12 @@ am_libepson2_la_OBJECTS = libepson2_la-epson2.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_OBJECTS = $(am_libepsonds_la_OBJECTS)  libfujitsu_la_LIBADD =  am_libfujitsu_la_OBJECTS = libfujitsu_la-fujitsu.lo  libfujitsu_la_OBJECTS = $(am_libfujitsu_la_OBJECTS) @@ -654,6 +660,18 @@ 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 \ +	$(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 \ @@ -1505,24 +1523,24 @@ SOURCES = $(libabaton_la_SOURCES) $(libagfafocus_la_SOURCES) \  	$(libdll_la_SOURCES) $(libdll_preload_la_SOURCES) \  	$(libdmc_la_SOURCES) $(libepjitsu_la_SOURCES) \  	$(libepson_la_SOURCES) $(libepson2_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) $(libpint_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) $(libpint_la_SOURCES) \  	$(libpixma_la_SOURCES) $(libplustek_la_SOURCES) \  	$(libplustek_pp_la_SOURCES) $(libpnm_la_SOURCES) \  	$(libqcam_la_SOURCES) $(libricoh_la_SOURCES) \ @@ -1552,6 +1570,7 @@ SOURCES = $(libabaton_la_SOURCES) $(libagfafocus_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) \ @@ -1638,24 +1657,24 @@ DIST_SOURCES = $(libabaton_la_SOURCES) $(libagfafocus_la_SOURCES) \  	$(libdll_la_SOURCES) $(libdll_preload_la_SOURCES) \  	$(libdmc_la_SOURCES) $(libepjitsu_la_SOURCES) \  	$(libepson_la_SOURCES) $(libepson2_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) $(libpint_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) $(libpint_la_SOURCES) \  	$(libpixma_la_SOURCES) $(libplustek_la_SOURCES) \  	$(libplustek_pp_la_SOURCES) $(libpnm_la_SOURCES) \  	$(libqcam_la_SOURCES) $(libricoh_la_SOURCES) \ @@ -1916,31 +1935,32 @@ EXTRA_DIST = sane_strstatus.c stubs.c saned.conf.in abaton.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 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 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 \ +	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 \ +	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 p5.conf.in \  	p5_device.c pixma.conf.in pixma_sane_options.c \ @@ -1984,7 +2004,7 @@ 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 fujitsu.conf genesys.conf gphoto2.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\  	       leo.conf lexmark.conf ma1509.conf magicolor.conf \ @@ -2020,7 +2040,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 libfujitsu.la libgenesys.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 \ @@ -2054,7 +2074,7 @@ 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-fujitsu.la libsane-genesys.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 \ @@ -2244,6 +2264,18 @@ 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 + +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_JPEG_LO@ $(JPEG_LIBS) $(USB_LIBS) $(MATH_LIB) $(RESMGR_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 @@ -2848,6 +2880,9 @@ libepson.la: $(libepson_la_OBJECTS) $(libepson_la_DEPENDENCIES) $(EXTRA_libepson  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) @@ -3055,6 +3090,9 @@ libsane-epson.la: $(libsane_epson_la_OBJECTS) $(libsane_epson_la_DEPENDENCIES) $  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) @@ -3347,6 +3385,12 @@ distclean-compile:  @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-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@ @@ -3446,6 +3490,7 @@ distclean-compile:  @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@ @@ -3539,14 +3584,14 @@ distclean-compile:  @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 $< +@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  @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 `$(CYGPATH_W) '$<'` +@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 $@ $< @@ -3814,6 +3859,48 @@ libepson2_la-epson2-cct.lo: epson2-cct.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) $(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 +  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 @@ -4507,6 +4594,13 @@ libsane_epson2_la-epson2-s.lo: epson2-s.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) $(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 diff --git a/backend/avision.c b/backend/avision.c index 74ffe80..146125c 100644 --- a/backend/avision.c +++ b/backend/avision.c @@ -39,25 +39,22 @@     ***************************************************************************** -   This backend is based upon the Tamarack backend and adapted to the Avision -   scanners by René Rebe and Meino Cramer. -        This file implements a SANE backend for the Avision SCSI Scanners (like the     AV 630 / 620 (CS) ...) and some Avision (OEM) USB scanners (like the HP 53xx,     74xx, Minolta FS-V1 ...) or Fujitsu ScanPartner with the AVISION SCSI-2/3 -   or USB command set. +   or USB command set and written by René Rebe and Meino Cramer. + +   Copyright 2002 - 2015 by +               	"Ren Rebe" <rene@exactcode.de> +     Copyright 1999, 2000, 2001 by                  "René Rebe" <rene@exactcode.de>                  "Meino Christian Cramer" <mccramer@s.netic.de>     Copyright 2002 by -                "René Rebe" <rene@exactcode.de>                  "Jose Paulo Moitinho de Almeida" <moitinho@civil.ist.utl.pt> -   Copyright 2003, 2004, 2005, 2006, 2007 by -                "René Rebe" <rene@exactcode.de> -        Copyright 2010, 2011 by                  "Mike Kelly" <mike@piratehaven.org> @@ -167,444 +164,451 @@ static Avision_HWEntry Avision_Device_List [] =      { "AVISION", "AV100CS",        0, 0,        "Avision", "AV100CS", -      0,0}, +      0},      /* status="untested" */      { "AVISION", "AV100IIICS",        0, 0,        "Avision", "AV100IIICS", -      0,0}, +      0},      /* status="untested" */      { "AVISION", "AV100S",        0, 0,        "Avision", "AV100S", -      0,0}, +      0},      /* status="untested" */      { NULL, NULL,        0x0638, 0x0A27,        "Avision", "AV120", -      AV_INT_STATUS,0}, +      AV_INT_STATUS},      /* comment="sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A3C,        "Avision", "AV121", -      AV_INT_BUTTON | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA,0}, +      AV_INT_BUTTON | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA},      /* comment="sheetfed scanner" */      /* status="good" */      { NULL, NULL,        0x0638, 0x0A33,        "Avision", "AV122", -      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET,0}, +      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", -      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_NOT_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET,0}, +      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_NOT_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET},      /* comment="sheetfed duplex scanner" */      /* status="good" */      { NULL, NULL,        0x0638, 0x0A24,        "Avision", "AV210", -      AV_INT_BUTTON  | AV_ACCEL_TABLE,0}, +      AV_INT_BUTTON  | AV_ACCEL_TABLE},      /* comment="sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A25,        "Avision", "AV210", -      AV_INT_BUTTON  | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN,0}, +      AV_INT_BUTTON  | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN},      /* comment="sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A3A,        "Avision", "AV210C2", -      AV_INT_BUTTON | AV_GRAY_MODES,0}, +      AV_INT_BUTTON | AV_GRAY_MODES},      /* comment="sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A2F,        "Avision", "AV210C2-G", -      AV_INT_BUTTON | AV_GRAY_MODES,0}, +      AV_INT_BUTTON | AV_GRAY_MODES},      /* comment="sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x1A35,        "Avision", "AV210D2+", -      AV_INT_BUTTON, AV_USE_GRAY_FILTER}, +      AV_INT_BUTTON | AV_USE_GRAY_FILTER},      /* comment="sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A23,        "Avision", "AV220", -      AV_INT_BUTTON | AV_GRAY_MODES,0}, +      AV_INT_BUTTON | AV_GRAY_MODES},      /* comment="duplex! sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A2A,        "Avision", "AV220C2", -      AV_INT_BUTTON | AV_CANCEL_BUTTON,0}, +      AV_INT_BUTTON | AV_CANCEL_BUTTON},      /* comment="duplex! sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A2B,        "Avision", "AV220D2", -      AV_INT_BUTTON | AV_CANCEL_BUTTON,0}, +      AV_INT_BUTTON | AV_CANCEL_BUTTON}, +    /* comment="duplex! sheetfed scanner" */ +    /* status="complete" */ + +    { NULL, NULL, +      0x0638, 0x1A31, +      "Avision", "AV220D2+", +      AV_INT_BUTTON | AV_CANCEL_BUTTON | AV_USE_GRAY_FILTER},      /* comment="duplex! sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A2C,        "Avision", "AV220+", -      AV_INT_BUTTON | AV_CANCEL_BUTTON,0}, +      AV_INT_BUTTON | AV_CANCEL_BUTTON},      /* comment="duplex! sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A2D,        "Avision", "AV220C2-G", -      AV_INT_BUTTON | AV_CANCEL_BUTTON,0}, +      AV_INT_BUTTON | AV_CANCEL_BUTTON},      /* comment="duplex! sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A2E,        "Avision", "AV220C2-B", -      AV_INT_BUTTON | AV_CANCEL_BUTTON,0}, +      AV_INT_BUTTON | AV_CANCEL_BUTTON},      /* comment="duplex! sheetfed scanner" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A94,        "Avision", "AV220-G", -      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED, AV_FIRMWARE}, +      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_FIRMWARE},      /* comment="duplex! sheetfed scanner" */      /* status="complete" */      { "AVISION", "AV240SC",        0, 0,        "Avision", "AV240SC", -      0,0}, +      0},      /* status="untested" */      { "AVISION", "AV260CS",        0, 0,        "Avision", "AV260CS", -      0,0}, +      0},      /* status="untested" */      { "AVISION", "AV360CS",        0, 0,        "Avision", "AV360CS", -      0,0}, +      0},      /* status="untested" */      { "AVISION", "AV363CS",        0, 0,        "Avision", "AV363CS", -      0,0}, +      0},      /* status="untested" */      { "AVISION", "AV420CS",        0, 0,        "Avision", "AV420CS", -      0,0}, +      0},      /* status="untested" */      { "AVISION", "AV6120",        0, 0,        "Avision", "AV6120", -      0,0}, +      0},      /* status="untested" */      { NULL, "AV610",        0x0638, 0x0a18,        "Avision", "AV610", -      AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | AV_INT_BUTTON, 0}, +      AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x0638, 0x0a18,        "Avision", "AV600U Plus",        /* If this unit requires the AV_INT_STATUS flag, then we'll need to alter the code to deal with two different devices with the same USB id (AV610 above) */ -      AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | /* AV_INT_STATUS | */ AV_INT_BUTTON,0}, +      AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | /* AV_INT_STATUS | */ AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x0638, 0x0a5e,        "Avision", "AV610C2", -      AV_NO_BACKGROUND | AV_INT_BUTTON,0}, /* cancel button -> sense abort! */ +      AV_NO_BACKGROUND | AV_INT_BUTTON}, /* cancel button -> sense abort! */      /* status="good" */     { NULL, NULL,        0x0638, 0x0a41,       "Avision", "AM3000 Series", -      0,0}, +      0},      /* comment="MFD" */      /* status="basic" */      { NULL, NULL,        0x0638, 0x0a16,        "Avision", "DS610CU Scancopier", -      AV_INT_STATUS,0}, +      AV_INT_STATUS},      /* comment="1 pass, 600 dpi, A4" */      /* status="good" */      { "AVISION", "AV620CS",        0, 0,        "Avision", "AV620CS", -      0,0}, +      0},      /* comment="1 pass, 600 dpi" */      /* status="complete" */      { "AVISION", "AV620CS Plus",        0, 0,        "Avision", "AV620CS Plus", -      0,0}, +      0},      /* comment="1 pass, 1200 dpi" */      /* status="complete" */      { "AVISION", "AV630CS",        0, 0,        "Avision", "AV630CS", -      0,0}, +      0},      /* comment="1 pass, 1200 dpi" */      /* status="complete" */      { "AVISION", "AV630CSL",        0, 0,        "Avision", "AV630CSL", -      0,0}, +      0},      /* comment="1 pass, 1200 dpi" */      /* status="untested" */      { "AVISION", "AV6240",        0, 0,        "Avision", "AV6240", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A13,        "Avision", "AV600U", -      AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_SOFT_SCALE | AV_INT_STATUS | AV_NO_BUTTON,0}, +      AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_SOFT_SCALE | AV_INT_STATUS | AV_NO_BUTTON},      /* comment="1 pass, 600 dpi" */      /* status="good" */      { "AVISION", "AV660S",        0, 0,        "Avision", "AV660S", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV680S",        0, 0,        "Avision", "AV680S", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV690U",        0, 0,        "Avision", "AV690U", -      0,0}, +      0},      /* comment="1 pass, 2400 dpi" */      /* status="untested" */      { "AVISION", "AV800S",        0, 0,        "Avision", "AV800S", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV810C",        0, 0,        "Avision", "AV810C", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV820",        0, 0,        "Avision", "AV820", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV820C",        0, 0,        "Avision", "AV820C", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV820C Plus",        0, 0,        "Avision", "AV820C Plus", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV830C",        0, 0,        "Avision", "AV830C", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV830C Plus",        0, 0,        "Avision", "AV830C Plus", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV880",        0, 0,        "Avision", "AV880", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV880C",        0, 0,        "Avision", "AV880C", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="untested" */      { "AVISION", "AV3200C",        0, 0,        "Avision", "AV3200C", -      AV_NON_INTERLACED_DUPLEX_300 | AV_FASTER_WITH_FILTER,0}, +      AV_NON_INTERLACED_DUPLEX_300 | AV_FASTER_WITH_FILTER},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV3200SU",        0x0638, 0x0A4E,        "Avision", "AV3200SU", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV3730SU",        0x0638, 0x0A4F,        "Avision", "AV3730SU", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV3750SU",        0x0638, 0x0A65,        "Avision", "AV3750SU", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV3800C",        0, 0,        "Avision", "AV3800C", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "AV3850SU",        0x0638, 0x0a66,        "Avision", "AV3850SU", -      0,0}, +      0},      /* comment="1 pass, ??? dpi" */      /* status="complete" */      { "AVISION", "FB6000E",        0, 0,        "Avision", "FB6000E", -      AV_NON_INTERLACED_DUPLEX_300,0}, +      AV_NON_INTERLACED_DUPLEX_300},      /* comment="1 pass, 1200 dpi, A3 - duplex! - zero edge!" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0a82,        "Avision", "FB6080E", -      AV_NON_INTERLACED_DUPLEX_300,0}, +      AV_NON_INTERLACED_DUPLEX_300},      /* comment="1 pass, 1200 dpi, A3 - duplex! - zero edge!" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0a84,        "Avision", "FB2080E", -      0,0}, +      0},      /* comment="1 pass, 600 dpi, zero-edge" ASIC 7 */      /* status="basic" */      { "AVISION", "AV8000S",        0, 0,        "Avision", "AV8000S", -      AV_DOES_NOT_KEEP_WINDOW,0}, +      AV_DOES_NOT_KEEP_WINDOW},      /* comment="1 pass, 1200 dpi, A3" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0a4d,        "Avision", "AV8050U", -      AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA,0}, +      AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA},      /* comment="1 pass, 1200 dpi, A3 - duplex!" */      /* status="complete" */      { "AVISION", "AV8300",        0x0638, 0x0A40,        "Avision", "AV8300", -      AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA,0}, +      AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA},      /* comment="1 pass, 1200 dpi, A3 - duplex!" */      /* status="complete" */      { "AVISION", "AV8350",        0x0638, 0x0A68,        "Avision", "AV8350", -      AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA,0}, +      AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA},      /* comment="1 pass, 1200 dpi, A3 - duplex!" */      /* status="complete" */      { NULL, NULL,        0x0638, 0x0A61,        "Avision", "IT8300", -      AV_NON_INTERLACED_DUPLEX_300 | AV_ACCEL_TABLE,0}, +      AV_NON_INTERLACED_DUPLEX_300 | AV_ACCEL_TABLE},      /* comment="1 pass, 1200 dpi, A3 - duplex!, LCD screen, paper sensors" */      /* status="good" */      { NULL, NULL,         0x0638, 0x0AA1,        "Avision", "@V2500", -      0,0}, +      0},      /* comment="" */      /* status="untested" */      { NULL, NULL,        0x0638, 0x0A45,        "Avision", "@V5100", -      0,0}, +      0},      /* comment="1 pass, 1200 dpi, A3 - duplex!, LCD screen, paper sensors" */      /* status="good" */      { "AVISION", "AVA3",        0, 0,        "Avision", "AVA3", -      AV_FORCE_A3,0}, +      AV_FORCE_A3},      /* comment="1 pass, 600 dpi, A3" */      /* status="basic" */ @@ -613,21 +617,21 @@ static Avision_HWEntry Avision_Device_List [] =      { "HP",      "ScanJet 5300C",        0x03f0, 0x0701,        "Hewlett-Packard", "ScanJet 5300C", -      AV_INT_STATUS,0}, +      AV_INT_STATUS},      /* comment="1 pass, 2400 dpi - some FW revisions have x-axis image scaling problems over 1200 dpi" */      /* status="complete" */      { "HP",      "ScanJet 5370C",        0x03f0, 0x0701,        "Hewlett-Packard", "ScanJet 5370C", -      AV_MULTI_CALIB_CMD | AV_INT_STATUS, 0 }, +      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,0}, +      AV_LIGHT_CHECK_BOGUS | AV_NO_64BYTE_ALIGN | AV_INT_STATUS},      /* comment="1 pass, 2400 dpi - dual USB/SCSI interface" */      /* status="good" */ @@ -635,14 +639,14 @@ static Avision_HWEntry Avision_Device_List [] =      { "hp",      "scanjet 7450c",        0x03f0, 0x0801,        "Hewlett-Packard", "ScanJet 7450c", -      AV_NO_64BYTE_ALIGN | AV_INT_STATUS,0}, +      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", -      AV_NO_64BYTE_ALIGN | AV_INT_STATUS,0}, +      AV_NO_64BYTE_ALIGN | AV_INT_STATUS},      /* comment="1 pass, 1200 dpi - dual USB/SCSI interface" */      /* status="good" */ @@ -650,7 +654,7 @@ static Avision_HWEntry Avision_Device_List [] =      { "HP",      "C9930A",        0x03f0, 0x0b01,        "Hewlett-Packard", "ScanJet 8200", -      0, AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE }, +      AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},      /* comment="1 pass, 4800 (?) dpi - USB 2.0" */      /* status="good" */ @@ -658,7 +662,7 @@ static Avision_HWEntry Avision_Device_List [] =      { "HP",      "C9930A",        0x03f0, 0x0b01,        "Hewlett-Packard", "ScanJet 8250", -      0, AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE }, +      AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},      /* comment="1 pass, 4800 (?) dpi - USB 2.0" */      /* status="good" */  #endif @@ -666,7 +670,7 @@ static Avision_HWEntry Avision_Device_List [] =      { "HP", "C9930A",        0x03f0, 0x3905,        "Hewlett-Packard", "ScanJet 8270", -      0, AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE }, +      AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},      /* comment="1 pass, 4800 (?) dpi - USB 2.0" */      /* status="good" */ @@ -674,7 +678,7 @@ static Avision_HWEntry Avision_Device_List [] =      { "HP", "C9930A",        0x03f0, 0x0b01,        "Hewlett-Packard", "ScanJet 8290", -      0, AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE }, +      AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},      /* comment="1 pass, 4800 (?) dpi - USB 2.0 and SCSI - only SCSI tested so far" */      /* status="good" */ @@ -682,7 +686,7 @@ static Avision_HWEntry Avision_Device_List [] =      { "HP", "C9930A",        0x03f0, 0x3805,        "Hewlett-Packard", "ScanJet 8300", -      0,0}, +      0},      /* comment="1 pass, 4800 (?) dpi - USB 2.0" */      /* status="good" */ @@ -690,14 +694,14 @@ static Avision_HWEntry Avision_Device_List [] =      { "HP", "C9930A",        0x03f0, 0x3805,        "Hewlett-Packard", "ScanJet 8350", -      0,0}, +      0},      /* comment="1 pass, 4800 (?) dpi - USB 2.0" */      /* status="good" */      { "HP", "C9930A",        0x03f0, 0x3805,        "Hewlett-Packard", "ScanJet 8390", -      0,0}, +      0},      /* comment="1 pass, 4800 (?) dpi - USB 2.0" */      /* status="good" */ @@ -705,79 +709,79 @@ static Avision_HWEntry Avision_Device_List [] =      { "Minolta", "#2882",        0, 0,        "Minolta", "Dimage Scan Dual I", -      AV_FORCE_FILM | AV_NO_START_SCAN,0}, /* not AV_FILMSCANNER (no frame control) */ +      AV_FORCE_FILM | AV_NO_START_SCAN}, /* not AV_FILMSCANNER (no frame control) */      /* status="basic" */      { "Minolta", "#2887",        0, 0,        "Minolta", "Scan Multi Pro", -      AV_FORCE_FILM | AV_NO_START_SCAN,0}, /* AV_FILMSCANNER (frame control)? */ +      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,0}, +      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,0}, +      AV_FILMSCANNER | AV_ONE_CALIB_CMD},      /* comment="1 pass, film-scanner" */      /* status="untested" */      { "MINOLTA", "FS-V3",        0x0686, 0x400d,        "Minolta", "Dimage Scan Dual III", -      AV_FILMSCANNER | AV_ONE_CALIB_CMD | AV_ACCEL_TABLE ,0}, +      AV_FILMSCANNER | AV_ONE_CALIB_CMD | AV_ACCEL_TABLE},      /* comment="1 pass, film-scanner" */      /* status="good" */      { "MINOLTA", "FS-V4",        0x0686, 0x400e,        "Minolta", "Dimage Scan Elite 5400", -      AV_FILMSCANNER | AV_ONE_CALIB_CMD | /*AV_ACCEL_TABLE |*/ AV_NO_START_SCAN,0}, +      AV_FILMSCANNER | AV_ONE_CALIB_CMD | /*AV_ACCEL_TABLE |*/ AV_NO_START_SCAN},      /* comment="1 pass, film-scanner" */      /* status="good" */      { "QMS", "SC-110",        0x0638, 0x0a15,        "Minolta-QMS", "SC-110", -      0,0}, +      0},      /* comment="" */      /* status="untested" */      { "QMS", "SC-215",        0x0638, 0x0a16,        "Minolta-QMS", "SC-215", -      0,0}, +      0},      /* comment="" */      /* status="good" */      { "MITSBISH", "MCA-ADFC",        0, 0,        "Mitsubishi", "MCA-ADFC", -      0,0}, +      0},      /* status="untested" */      { "MITSBISH", "MCA-S1200C",        0, 0,        "Mitsubishi", "S1200C", -      0,0}, +      0},      /* status="untested" */      { "MITSBISH", "MCA-S600C",        0, 0,        "Mitsubishi", "S600C", -      0,0}, +      0},      /* status="untested" */      { "MITSBISH", "SS600",        0, 0,        "Mitsubishi", "SS600", -      0,0}, +      0},      /* status="good" */      /* The next are all untested ... */ @@ -785,209 +789,209 @@ static Avision_HWEntry Avision_Device_List [] =      { "FCPA", "ScanPartner",        0, 0,        "Fujitsu", "ScanPartner", -      AV_FUJITSU,0}, +      AV_FUJITSU},      /* status="untested" */      { "FCPA", "ScanPartner 10",        0, 0,        "Fujitsu", "ScanPartner 10", -      AV_FUJITSU,0}, +      AV_FUJITSU},      /* status="untested" */      { "FCPA", "ScanPartner 10C",        0, 0,        "Fujitsu", "ScanPartner 10C", -      AV_FUJITSU,0}, +      AV_FUJITSU},      /* status="untested" */      { "FCPA", "ScanPartner 15C",        0, 0,        "Fujitsu", "ScanPartner 15C", -      AV_FUJITSU,0}, +      AV_FUJITSU},      /* status="untested" */      { "FCPA", "ScanPartner 300C",        0, 0,        "Fujitsu", "ScanPartner 300C", -      0,0}, +      0},      /* status="untested" */      { "FCPA", "ScanPartner 600C",        0, 0,        "Fujitsu", "ScanPartner 600C", -      0,0}, +      0},      /* status="untested" */      { "FCPA", "ScanPartner 620C",        0, 0,        "Fujitsu", "ScanPartner 620C", -      AV_LIGHT_CHECK_BOGUS,0}, +      AV_LIGHT_CHECK_BOGUS},      /* status="good" */      { "FCPA", "ScanPartner Jr",        0, 0,        "Fujitsu", "ScanPartner Jr", -      0,0}, +      0},      /* status="untested" */      { "FCPA", "ScanStation",        0, 0,        "Fujitsu", "ScanStation", -      0,0}, +      0},      /* status="untested" */      { NULL, NULL,        0x04c5, 0x1029,        "Fujitsu", "fi-4010CU", -      0,0}, +      0},      /* status="untested" */      { NULL, NULL,        0x04c5, 0x10ef,        "Fujitsu", "fi-5015C", -      0,0}, +      0},      /* status="good" */      { NULL, NULL,        0x040a, 0x6001,        "Kodak", "i30", -      AV_INT_BUTTON | AV_GRAY_MODES,0}, +      AV_INT_BUTTON | AV_GRAY_MODES},      /* status="untested" */      { NULL, NULL,        0x040a, 0x6002,        "Kodak", "i40", -      AV_INT_BUTTON | AV_GRAY_MODES,0}, +      AV_INT_BUTTON | AV_GRAY_MODES},      /* status="basic" */      { NULL, NULL,        0x040a, 0x6003,        "Kodak", "i50", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */  #ifdef FAKE_ENTRIES_FOR_DESC_GENERATION      { NULL, NULL,        0x040a, 0x6003,        "Kodak", "i55", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */  #endif      { NULL, NULL,        0x040a, 0x6004,        "Kodak", "i60", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */  #ifdef FAKE_ENTRIES_FOR_DESC_GENERATION      { NULL, NULL,        0x040a, 0x6004,        "Kodak", "i65", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */  #endif      { NULL, NULL,        0x040a, 0x6005,        "Kodak", "i80", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},       /* status="good" */       { "iVina", "1200U",        0x0638, 0x0268,        "iVina", "1200U", -      0,0}, +      0},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x0424,        "Visioneer", "Strobe XP 450", -      AV_INT_BUTTON  | AV_ACCEL_TABLE,0}, +      AV_INT_BUTTON  | AV_ACCEL_TABLE},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0491,        "Visioneer", "Strobe XP 450-G", -      AV_INT_BUTTON  | AV_ACCEL_TABLE,0}, +      AV_INT_BUTTON  | AV_ACCEL_TABLE},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0479,        "Visioneer", "Strobe XP 470", -      AV_INT_BUTTON  | AV_ACCEL_TABLE,0}, +      AV_INT_BUTTON  | AV_ACCEL_TABLE},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x048F,        "Visioneer", "Strobe XP 470-G", -      AV_INT_BUTTON  | AV_ACCEL_TABLE,0}, +      AV_INT_BUTTON  | AV_ACCEL_TABLE},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0420,        "Visioneer", "9320", -      0,0}, +      0},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0421,        "Visioneer", "9450", -      AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_NO_BUTTON, AV_NO_TUNE_SCAN_LENGTH}, +      AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_NO_BUTTON | AV_NO_TUNE_SCAN_LENGTH},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x047A,        "Visioneer", "9450-G", -      0,0}, +      0},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0422,        "Visioneer", "9550", -      0,0}, +      0},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0390,        "Visioneer", "9650", -      0,0}, +      0},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x047B,        "Visioneer", "9650-G", -      0,0}, +      0},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0423,        "Visioneer", "9750", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0493,        "Visioneer", "9750-G", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0497,        "Visioneer", "Patriot 430", -      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET,0}, +      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 scanner" */        /* status="complete" */ @@ -995,7 +999,7 @@ static Avision_HWEntry Avision_Device_List [] =      { NULL, NULL,        0x04a7, 0x048F,        "Visioneer", "Patriot 470", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},        /* comment="sheetfed scanner" */        /* status="complete" */  #endif @@ -1003,150 +1007,150 @@ static Avision_HWEntry Avision_Device_List [] =      { NULL, NULL,        0x04a7, 0x0498,        "Visioneer", "Patriot 680", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x0499,        "Visioneer", "Patriot 780", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},        /* comment="sheetfed scanner" */        /* status="complete" */      { NULL, NULL,        0x04a7, 0x049C,        "Xerox", "DocuMate150", -      AV_INT_BUTTON | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_BACKGROUND_QUIRK,0}, +      AV_INT_BUTTON | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_BACKGROUND_QUIRK},      /* status="good" */      { NULL, NULL,        0x04a7, 0x0477,        "Xerox", "DocuMate152", -      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET | AV_BACKGROUND_QUIRK,0}, +      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET | AV_BACKGROUND_QUIRK},      /* status="good" */      { NULL, NULL,        0x04a7, 0x049D,        "Xerox", "DocuMate162", -      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET | AV_BACKGROUND_QUIRK,0}, +      AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET | AV_BACKGROUND_QUIRK},      /* status="good" */      { NULL, NULL,        0x04a7, 0x0448,        "Xerox", "DocuMate250", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x0490,        "Xerox", "DocuMate250-G", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x0449,        "Xerox", "DocuMate252", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x048C,        "Xerox", "DocuMate252-G", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x0476,        "Xerox", "DocuMate232", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x044c,        "Xerox", "DocuMate262", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x048D,        "Xerox", "DocuMate262-G", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x04a7,        "Xerox", "DocuMate262i", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="good" */      { NULL, NULL,        0x04a7, 0x0475,        "Xerox", "DocuMate272", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x048E,        "Xerox", "DocuMate272-G", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x0446,        "Xerox", "DocuMate510", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x0495,        "Xerox", "DocuMate512", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x047c,        "Xerox", "DocuMate510-G", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x0447,        "Xerox", "DocuMate520", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x0492,        "Xerox", "DocuMate520-G", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */  #ifdef FAKE_ENTRIES_FOR_DESC_GENERATION      { NULL, NULL,        0x04a7, 0x0498,        "Xerox", "DocuMate632", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */  #endif      { NULL, NULL,        0x04a7, 0x0478,        "Xerox", "DocuMate752", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */      { NULL, NULL,        0x04a7, 0x049A,        "Xerox", "DocuMate752", -      AV_INT_BUTTON,0}, +      AV_INT_BUTTON},      /* status="untested" */  #ifdef FAKE_ENTRIES_FOR_DESC_GENERATION      { NULL, NULL,        0x0638, 0x0a16,        "OKI", "S700 Scancopier", -      0,0}, +      0},      /* comment="1 pass, 600 dpi, A4" */      /* status="good" */  #endif @@ -1154,14 +1158,14 @@ static Avision_HWEntry Avision_Device_List [] =      { "B+H", "2000F",        0, 0,        "Bell+Howell", "2000F", -      0,0}, +      0},      /* comment="1 pass, ??? dpi, A4" */      /* status="basic" */      { NULL, NULL,        0x0482, 0x0335,        "Kyocera", "FS-1016MFP", -      0,0}, +      0},      /* comment="1 pass, ??? dpi, A4" */      /* status="untested" */ @@ -1203,7 +1207,7 @@ Lexmark X4500 MFP      { NULL, NULL,        0, 0,        NULL, NULL, -      0,0}  +      0}     };  #if 0 @@ -3208,7 +3212,7 @@ get_accessories_info (Avision_Scanner* s)    dev->inquiry_adf |= result [0]; -  if (dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) +  if (dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX)    {      if (result[0] == 1)      { @@ -3765,14 +3769,14 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type,    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: mike@piratehaven.org (the Avision backend maintainer)\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_type2 & AV_FIRMWARE) +  if (Avision_Device_List [model_num].feature_type & AV_FIRMWARE)    {        DBG (3, "attach: reading firmware status\n");        status = get_firmware_status (&av_con); @@ -4211,7 +4215,7 @@ get_double ( &(result[48] ) ));    }    dev->inquiry_tune_scan_length = BIT(result[94],2); -  if (Avision_Device_List [model_num].feature_type2 & AV_NO_TUNE_SCAN_LENGTH) +  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); @@ -4278,7 +4282,9 @@ get_double ( &(result[48] ) ));    else      dev->scsi_buffer_size = sanei_scsi_max_request_size; -  if (dev->inquiry_asic_type >= AV_ASIC_C5) +  if (dev->inquiry_asic_type > AV_ASIC_C7 && dev->inquiry_asic_type < AV_ASIC_OA980) +    dev->read_stripe_size = 16; +  else if (dev->inquiry_asic_type >= AV_ASIC_C5)      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 ... */ @@ -5142,7 +5148,7 @@ send_gamma (Avision_Scanner* s)    switch (dev->inquiry_asic_type)      {      case AV_ASIC_Cx: -    case AV_ASIC_C1: /* from avision code */ +    case AV_ASIC_C1:        gamma_table_raw_size = 4096;        gamma_table_size = 2048;        break; @@ -5150,10 +5156,6 @@ send_gamma (Avision_Scanner* s)        gamma_table_raw_size = 256;        gamma_table_size = 256;        break; -    case AV_ASIC_C6: /* SPEC claims: 256 ... ? */ -    case AV_ASIC_C7: -      gamma_table_raw_size = 512; -      gamma_table_size = 512;        break;      case AV_ASIC_OA980:        gamma_table_raw_size = 4096; @@ -5164,7 +5166,8 @@ send_gamma (Avision_Scanner* s)        gamma_table_size = 256;        break;      default: -      gamma_table_raw_size = gamma_table_size = 4096; +      gamma_table_raw_size = 512; /* SPEC claims: 256 ... ? */ +      gamma_table_size = 512;      }    gamma_values = gamma_table_size / 256; @@ -5678,8 +5681,9 @@ set_window (Avision_Scanner* s)      }    } -  if (s->val[OPT_PAPERLEN].w) +  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) )      {  @@ -5780,7 +5784,7 @@ set_window (Avision_Scanner* s)    else {      if (dev->hw->feature_type & AV_FASTER_WITH_FILTER)        cmd.window.avision.bitset1 |= AVISION_FILTER_GREEN; -    else if (dev->hw->feature_type2 & AV_USE_GRAY_FILTER) +    else if (dev->hw->feature_type & AV_USE_GRAY_FILTER)        cmd.window.avision.bitset1 |= AVISION_FILTER_GRAY;      else        cmd.window.avision.bitset1 |= AVISION_FILTER_NONE; @@ -6182,7 +6186,7 @@ do_eof (Avision_Scanner *s)    /* we can now mark the rear data as valid */    if (s->avdimen.interlaced_duplex || -      (s->hw->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX)) { +      (s->hw->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX)) {      DBG (3, "do_eof: toggling duplex rear data valid\n");      s->duplex_rear_valid = !s->duplex_rear_valid;      DBG (3, "do_eof: duplex rear data valid: %x\n", @@ -6262,11 +6266,6 @@ init_options (Avision_Scanner* s)    /* Init the SANE option from the scanner inquiry data */ -  dev->x_range.max = SANE_FIX ( (int)dev->inquiry_x_ranges[s->source_mode_dim]); -  dev->x_range.quant = 0; -  dev->y_range.max = SANE_FIX ( (int)dev->inquiry_y_ranges[s->source_mode_dim]); -  dev->y_range.quant = 0; -      switch (dev->inquiry_asic_type) {      case AV_ASIC_C2:        dev->dpi_range.min = 100; @@ -6331,6 +6330,11 @@ init_options (Avision_Scanner* s)    s->source_mode = match_source_mode (dev, s->val[OPT_SOURCE].s);    s->source_mode_dim = match_source_mode_dim (s->source_mode); +  dev->x_range.max = SANE_FIX ( (int)dev->inquiry_x_ranges[s->source_mode_dim]); +  dev->x_range.quant = 0; +  dev->y_range.max = SANE_FIX ( (int)dev->inquiry_y_ranges[s->source_mode_dim]); +  dev->y_range.quant = 0; +    /* resolution */    s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;    s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; @@ -6667,7 +6671,7 @@ init_options (Avision_Scanner* s)    /* 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_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX)) +  if (!(s->hw->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX))      s->opt[OPT_ADF_FLIP].cap |= SANE_CAP_INACTIVE;    s->opt[OPT_ADF_FLIP].name = "flip-page";    s->opt[OPT_ADF_FLIP].title = "Flip document after duplex scanning"; @@ -6782,7 +6786,7 @@ reader_process (void *data)      return SANE_STATUS_NO_MEM;    /* start scan ? */ -  if ((deinterlace == NONE && !((dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && s->duplex_rear_valid)) || +  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))      {        /* reserve unit - in the past we did this in open - but the @@ -6820,7 +6824,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_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2))) +     (dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2)))      {        if (!s->duplex_rear_valid) { /* create new file for writing */  	DBG (3, "reader_process: opening duplex rear file for writing.\n"); @@ -6954,11 +6958,15 @@ reader_process (void *data)  	  /* only EOF on the second stripe, as otherwise the rear page  	     is shorter */  	  if (status == SANE_STATUS_EOF && deinterlace == STRIPE) { -	    static int already_eof = 0; -	    if (!already_eof) { -	      DBG (5, "reader_process: first EOF on stripe interlace: hiding.\n"); -	      status = SANE_STATUS_GOOD; -	      already_eof = 1; +	    if (dev->inquiry_asic_type > AV_ASIC_C7 && dev->inquiry_asic_type < AV_ASIC_OA980) { +	      this_read = 0; +	    } else { +	      static int already_eof = 0; +	      if (!already_eof) { +		DBG (5, "reader_process: first EOF on stripe interlace: hiding.\n"); +		status = SANE_STATUS_GOOD; +		already_eof = 1; +	      }  	    }  	  } @@ -7047,7 +7055,7 @@ reader_process (void *data)  	  DBG (9, "reader_process: after deinterlacing: useful_bytes: %d, stripe_fill: %d\n",  	       useful_bytes, stripe_fill);  	} -      if (dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2) && !s->duplex_rear_valid) { +      if (dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2) && !s->duplex_rear_valid) {          /* Here we flip the image by writing the lines from the end of the file to the beginning. */  	unsigned int absline = (processed_bytes - stripe_fill) / s->avdimen.hw_bytes_per_line;  	unsigned int abslines = absline + useful_bytes / s->avdimen.hw_bytes_per_line; @@ -7454,7 +7462,7 @@ reader_process (void *data)    /* Eject film holder and/or release_unit - but only for       non-duplex-rear / non-virtual scans. */    if ((deinterlace != NONE && s->duplex_rear_valid) || -     ((dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2) && s->duplex_rear_valid)) +     ((dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2) && s->duplex_rear_valid))      {        DBG (1, "reader_process: virtual duplex scan - no device cleanup!\n");      } @@ -7477,7 +7485,7 @@ reader_process (void *data)        }      } -  if ((dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && s->page % 2) { +  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) {        if (s->val[OPT_ADF_FLIP].w) { @@ -7891,7 +7899,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle)    init_options (s);    if (dev->inquiry_duplex_interlaced || dev->scanner_type == AV_FILM || -      dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) { +      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); @@ -8188,7 +8196,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option,  	  dev->y_range.max =  	    SANE_FIX ( dev->inquiry_y_ranges[s->source_mode_dim]); -          if (s->hw->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX) { +          if (s->hw->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX) {              s->opt[OPT_ADF_FLIP].cap &= ~SANE_CAP_INACTIVE;            } else {              s->opt[OPT_ADF_FLIP].cap |= SANE_CAP_INACTIVE; @@ -8284,16 +8292,9 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters* params)      }    if (params) { +    *params = s->params;      /* add background raster lines */ -    s->params.lines += s->val[OPT_BACKGROUND].w; - -    /* copy structure members */ -    params->format = s->params.format; -    params->last_frame = s->params.last_frame; -    params->bytes_per_line = s->params.bytes_per_line; -    params->pixels_per_line = s->params.pixels_per_line; -    params->lines = s->params.lines; -    params->depth = s->params.depth; +    params->lines += s->val[OPT_BACKGROUND].w;    }    return SANE_STATUS_GOOD; diff --git a/backend/avision.h b/backend/avision.h index 14134e1..2122e09 100644 --- a/backend/avision.h +++ b/backend/avision.h @@ -93,123 +93,119 @@ typedef struct Avision_HWEntry {    /* feature overwrites - as embedded CPUs have 16bit enums - this       would need a change ... */ -  enum {      /* force no calibration */ -    AV_NO_CALIB = (1<<0), +  #define AV_NO_CALIB ((uint64_t)1<<0)      /* force all in one command calibration */ -    AV_ONE_CALIB_CMD = (1<<1), +  #define AV_ONE_CALIB_CMD ((uint64_t)1<<1)      /* no gamma table */ -    AV_NO_GAMMA = (1<<2), +  #define AV_NO_GAMMA ((uint64_t)1<<2)      /* light check is bogus */ -    AV_LIGHT_CHECK_BOGUS = (1<<3), +  #define AV_LIGHT_CHECK_BOGUS ((uint64_t)1<<3)      /* no button though the device advertise it */ -    AV_NO_BUTTON = (1<<4), +  #define AV_NO_BUTTON ((uint64_t)1<<4)      /* if the scan area needs to be forced to A3 */ -    AV_FORCE_A3 = (1<<5), +  #define AV_FORCE_A3 ((uint64_t)1<<5)      /* if the scan area and resolution needs to be forced for films */ -    AV_FORCE_FILM = (1<<6), +  #define AV_FORCE_FILM ((uint64_t)1<<6)      /* does not suport, or very broken background (added for AV610C2) */ -    AV_NO_BACKGROUND = (1<<7), +  #define AV_NO_BACKGROUND ((uint64_t)1<<7)      /* is film scanner - no detection yet */ -    AV_FILMSCANNER = (1<<8), +  #define AV_FILMSCANNER ((uint64_t)1<<8)      /* fujitsu adaption */ -    AV_FUJITSU = (1<<9), +  #define AV_FUJITSU ((uint64_t)1<<9)      /* gray calibration data has to be uploaded on the blue channel ... ? */ -    AV_GRAY_CALIB_BLUE = (1<<10), +  #define AV_GRAY_CALIB_BLUE ((uint64_t)1<<10)      /* Interrupt endpoint button readout (so far AV220) */ -    AV_INT_BUTTON = (1<<11), +  #define AV_INT_BUTTON ((uint64_t)1<<11)      /* send acceleration table ... */ -    AV_ACCEL_TABLE = (1<<12), +  #define AV_ACCEL_TABLE ((uint64_t)1<<12)      /* non-interlaced scanns up to 300 dpi (AV32xx / AV83xx) */ -    AV_NON_INTERLACED_DUPLEX_300 = (1<<13), +  #define AV_NON_INTERLACED_DUPLEX_300 ((uint64_t)1<<13)      /* do not read multiples of 64 bytes - stalls the USB chip */ -    AV_NO_64BYTE_ALIGN = (1<<14), +  #define AV_NO_64BYTE_ALIGN ((uint64_t)1<<14)      /* force channel-by-channel calibration */ -    AV_MULTI_CALIB_CMD = (1<<15), +  #define AV_MULTI_CALIB_CMD ((uint64_t)1<<15)      /* non color scans are faster with a filter applied (AV32xx) */ -    AV_FASTER_WITH_FILTER = (1<<16), +  #define AV_FASTER_WITH_FILTER ((uint64_t)1<<16)      /* interlaced data with 1 line distance */ -    AV_2ND_LINE_INTERLACED = (1<<17), +  #define AV_2ND_LINE_INTERLACED ((uint64_t)1<<17)      /* does not keep the window though it advertices so */ -    AV_DOES_NOT_KEEP_WINDOW = (1<<18), +  #define AV_DOES_NOT_KEEP_WINDOW ((uint64_t)1<<18)      /* does not keep the gamma though it advertices so */ -    AV_DOES_NOT_KEEP_GAMMA = (1<<19), +  #define AV_DOES_NOT_KEEP_GAMMA ((uint64_t)1<<19)      /* advertises ADF is BGR order, but isn't (or vice versa) */ -    AV_ADF_BGR_ORDER_INVERT = (1<<20), +  #define AV_ADF_BGR_ORDER_INVERT ((uint64_t)1<<20)      /* allows 12bit mode, though not flagged */ -    AV_12_BIT_MODE = (1<<21), +  #define AV_12_BIT_MODE ((uint64_t)1<<21)      /* very broken background raster */ -    AV_BACKGROUND_QUIRK = (1<<22), +  #define AV_BACKGROUND_QUIRK ((uint64_t)1<<22)      /* though marked as GRAY only the scanner can do GRAY modes */ -    AV_GRAY_MODES = (1<<23), +  #define AV_GRAY_MODES ((uint64_t)1<<23)      /* no seperate, single REAR scan (AV122, DM152, ...) */ -    AV_NO_REAR = (1<<24), +  #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 */ -    AV_SOFT_SCALE = (1<<25), +  #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 */ -    AV_DOES_KEEP_WINDOW = (1<<26), +  #define AV_DOES_KEEP_WINDOW ((uint64_t)1<<26)      /* does keep gamma though it does not advertice it */ -    AV_DOES_KEEP_GAMMA = (1<<27), +  #define AV_DOES_KEEP_GAMMA ((uint64_t)1<<27)      /* does the scanner contain a Cancel button? */ -    AV_CANCEL_BUTTON = (1<<28), +  #define AV_CANCEL_BUTTON ((uint64_t)1<<28)      /* is the rear image offset? */ -    AV_REAR_OFFSET = (1<<29), +  #define AV_REAR_OFFSET ((uint64_t)1<<29)      /* some devices do not need a START_SCAN, even hang with it */ -    AV_NO_START_SCAN = (1<<30), -     -    AV_INT_STATUS = (1<<31) +  #define AV_NO_START_SCAN ((uint64_t)1<<30) -    /* maybe more ...*/ -  } feature_type; -       -  /*second enum cause 32 bit int above is full*/ -  enum { +  #define AV_INT_STATUS ((uint64_t)1<<31) +      /* force no calibration */ -    AV_NO_TUNE_SCAN_LENGTH = (1<<0), +  #define AV_NO_TUNE_SCAN_LENGTH ((uint64_t)1<<32)      /* for gray scans, set grey filter */ -    AV_USE_GRAY_FILTER = (1<<1), +  #define AV_USE_GRAY_FILTER ((uint64_t)1<<33)      /* For (HP) scanners with flipping duplexers */ -    AV_ADF_FLIPPING_DUPLEX = (1<<2), +  #define AV_ADF_FLIPPING_DUPLEX ((uint64_t)1<<34)      /* For scanners which need to have their firmware read to properly function. */ -    AV_FIRMWARE = (1<<3) -  } feature_type2; +  #define AV_FIRMWARE ((uint64_t)1<<35) +     +    /* maybe more ...*/ +  uint64_t feature_type;  } Avision_HWEntry; diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 15dcc59..0b120fa 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -309,6 +309,8 @@           - set another unknown byte in buffermode for ssm2           - add another gettimeofday call at end of do_usb_cmd           - don't print 0 length line in hexdump +      v49 2015-03-18, MAN +         - initial support for DR-C125     SANE FLOW DIAGRAM @@ -358,7 +360,7 @@  #include "canon_dr.h"  #define DEBUG 1 -#define BUILD 48 +#define BUILD 49  /* values for SANE_DEBUG_CANON_DR env var:   - errors           5 @@ -1542,6 +1544,38 @@ init_model (struct scanner *s)      s->can_monochrome=0;    } +  else if (strstr (s->model_name,"DR-C125") +   || strstr (s->model_name,"DR-C225") +  ){ + +    /*confirmed settings*/ +    s->gray_interlace[SIDE_FRONT] = GRAY_INTERLACE_2510; +    s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_2510; +    s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_2510; +    s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_2510; +    s->duplex_interlace = DUPLEX_INTERLACE_2510; +    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*/ + +    /*only in Y direction, so we trash them in X*/ +    s->std_res_x[DPI_100]=0; +    s->std_res_x[DPI_150]=0; +    s->std_res_x[DPI_200]=0; +    s->std_res_x[DPI_240]=0; +    s->std_res_x[DPI_400]=0; + +    /*suspected settings*/ +    s->always_op = 0; +    s->fixed_width = 1; +    s->valid_x = 8.5 * 1200; +  } +    DBG (10, "init_model: finish\n");    return SANE_STATUS_GOOD; diff --git a/backend/canon_dr.conf.in b/backend/canon_dr.conf.in index e946d9b..453065b 100644 --- a/backend/canon_dr.conf.in +++ b/backend/canon_dr.conf.in @@ -150,6 +150,7 @@ option duplex-offset 400  usb 0x1083 0x163f  # DR-C125 +option duplex-offset 400  usb 0x1083 0x1640  # DR-P215 diff --git a/backend/dll.conf.in b/backend/dll.conf.in index a7e4b3e..ee6f2f1 100644 --- a/backend/dll.conf.in +++ b/backend/dll.conf.in @@ -24,6 +24,7 @@ dmc  epjitsu  #epson  epson2 +epsonds  fujitsu  #gphoto2  genesys diff --git a/backend/epjitsu.c b/backend/epjitsu.c index 08e78b2..7d987dc 100644 --- a/backend/epjitsu.c +++ b/backend/epjitsu.c @@ -146,6 +146,11 @@           - fix 150 dpi settings for fi-60F and fi-65F           - make adf_height_padding variable           - make white_factor variable +      v27 2015-01-24, MAN +         - don't override br_x and br_y +         - call change_params after changing page_width +      v28 2015-03-23, MAN +         - call get_hardware_status before starting scan     SANE FLOW DIAGRAM @@ -194,7 +199,7 @@  #include "epjitsu-cmd.h"  #define DEBUG 1 -#define BUILD 26 +#define BUILD 28  #ifndef MAX3    #define MAX3(a,b,c) ((a) > (b) ? ((a) > (c) ? a : c) : ((b) > (c) ? b : c)) @@ -1712,8 +1717,8 @@ sane_control_option (SANE_Handle handle, SANE_Int option,                return SANE_STATUS_GOOD;            s->page_width = FIXED_MM_TO_SCANNER_UNIT(val_c); -          *info |= SANE_INFO_RELOAD_OPTIONS; -          return SANE_STATUS_GOOD; +          *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; +          return change_params(s);          case OPT_PAGE_HEIGHT:            if (s->page_height == FIXED_MM_TO_SCANNER_UNIT(val_c)) @@ -1970,11 +1975,6 @@ change_params(struct scanner *s)      s->max_y = PIX_TO_SCANNER_UNIT( settings[i].max_y, settings[i].y_res );      s->min_y = PIX_TO_SCANNER_UNIT( settings[i].min_y, settings[i].y_res ); -    /* wrong place for this?*/ -    s->page_width = s->max_x; -    s->br_x = s->max_x; -    s->br_y = s->max_y; -      /*current dpi*/      s->setWindowCoarseCal = settings[i].sw_coarsecal;      s->setWindowCoarseCalLen = SET_WINDOW_LEN; @@ -2018,13 +2018,14 @@ change_params(struct scanner *s)      if (s->page_height < s->min_y && s->page_height > 0)         s->page_height = s->min_y;      if (s->tl_y + s->page_height > s->max_y) -       s->tl_y = s->max_y - s->adf_height_padding - s->page_height ; +       s->tl_y = s->max_y - s->adf_height_padding - s->page_height; +    if (s->tl_y < 0) +       s->tl_y = 0;      if (s->page_height > 0) {          s->br_y = s->tl_y + s->page_height;      } -    else -    { +    else {          s->br_y = s->max_y;      } @@ -2370,6 +2371,9 @@ sane_start (SANE_Handle handle)          s->side = !s->side;      } +    /* recent scanners need ghs called before scanning */ +    ret = get_hardware_status(s); +      /* ingest paper with adf */      if( s->source == SOURCE_ADF_BACK || s->source == SOURCE_ADF_FRONT       || (s->source == SOURCE_ADF_DUPLEX && s->side == SIDE_FRONT) ){ diff --git a/backend/epson2-commands.c b/backend/epson2-commands.c index 0c28eab..eccd4ba 100644 --- a/backend/epson2-commands.c +++ b/backend/epson2-commands.c @@ -680,8 +680,10 @@ esci_set_scanning_parameter(SANE_Handle handle, unsigned char *buf)  		return status;  	status = e2_cmd_simple(s, buf, 64); -	if (status != SANE_STATUS_GOOD) +	if (status != SANE_STATUS_GOOD) { +		DBG(1, "%s: invalid scanning parameters\n", __func__);  		return status; +	}  	return SANE_STATUS_GOOD;  } diff --git a/backend/epson2-io.c b/backend/epson2-io.c index 13adef4..4477963 100644 --- a/backend/epson2-io.c +++ b/backend/epson2-io.c @@ -110,8 +110,8 @@ e2_send(Epson_Scanner * s, void *buf, size_t buf_size, size_t reply_len,  }  ssize_t -e2_recv(Epson_Scanner * s, void *buf, ssize_t buf_size, -	    SANE_Status * status) +e2_recv(Epson_Scanner *s, void *buf, ssize_t buf_size, +	    SANE_Status *status)  {  	ssize_t n = 0; @@ -142,8 +142,9 @@ e2_recv(Epson_Scanner * s, void *buf, ssize_t buf_size,  	}  	if (n < buf_size) { -		DBG(1, "%s: expected = %lu, got = %ld\n", __func__, -		    (u_long) buf_size, (long) n); +		DBG(1, "%s: expected = %lu, got = %ld, canceling: %d\n", __func__, +		    (u_long) buf_size, (long) n, s->canceling); +  		*status = SANE_STATUS_IO_ERROR;  	} diff --git a/backend/epson2-ops.c b/backend/epson2-ops.c index d81deaf..5d8c84d 100644 --- a/backend/epson2-ops.c +++ b/backend/epson2-ops.c @@ -472,8 +472,10 @@ e2_set_tpu2_area(struct Epson_Scanner *s, int x, int y, int unit)  }  void -e2_add_depth(Epson_Device * dev, SANE_Word depth) +e2_add_depth(Epson_Device *dev, SANE_Int depth)  { +	DBG(10, "%s: add (bpp): %d\n", __func__, depth); +  	if (depth > dev->maxDepth)  		dev->maxDepth = depth; @@ -765,7 +767,7 @@ e2_discover_capabilities(Epson_Scanner *s)  	 * Check for the max. supported color depth and assign  	 * the values to the bitDepthList.  	 */ -	dev->depth_list = malloc(sizeof(SANE_Word) * 4); +	dev->depth_list = malloc(sizeof(SANE_Int) * (4 + 1));  	if (dev->depth_list == NULL) {  		DBG(1, "out of memory (line %d)\n", __LINE__);  		return SANE_STATUS_NO_MEM; @@ -776,9 +778,12 @@ e2_discover_capabilities(Epson_Scanner *s)  	/* maximum depth discovery */  	DBG(3, "discovering max depth, NAKs are expected\n"); -	if (dev->maxDepth >= 16 || dev->maxDepth == 0) { -		if (esci_set_data_format(s, 16) == SANE_STATUS_GOOD) -			e2_add_depth(dev, 16); +	/* add default depth */ +	e2_add_depth(dev, 8); + +	if (dev->maxDepth >= 12 || dev->maxDepth == 0) { +		if (esci_set_data_format(s, 12) == SANE_STATUS_GOOD) +			e2_add_depth(dev, 12);  	}  	if (dev->maxDepth >= 14 || dev->maxDepth == 0) { @@ -786,14 +791,11 @@ e2_discover_capabilities(Epson_Scanner *s)  			e2_add_depth(dev, 14);  	} -	if (dev->maxDepth >= 12 || dev->maxDepth == 0) { -		if (esci_set_data_format(s, 12) == SANE_STATUS_GOOD) -			e2_add_depth(dev, 12); +	if (dev->maxDepth >= 16 || dev->maxDepth == 0) { +		if (esci_set_data_format(s, 16) == SANE_STATUS_GOOD) +			e2_add_depth(dev, 16);  	} -	/* add default depth */ -	e2_add_depth(dev, 8); -  	DBG(1, "maximum supported color depth: %d\n", dev->maxDepth);  	/* @@ -1742,6 +1744,8 @@ e2_ext_read(struct Epson_Scanner *s)  	SANE_Status status = SANE_STATUS_GOOD;  	ssize_t buf_len = 0, read; +	DBG(18, "%s: begin\n", __func__); +  	/* did we passed everything we read to sane? */  	if (s->ptr == s->end) { @@ -1765,10 +1769,12 @@ e2_ext_read(struct Epson_Scanner *s)  		/* receive image data + error code */  		read = e2_recv(s, s->buf, buf_len + 1, &status); -		DBG(18, "%s: read %lu bytes\n", __func__, (unsigned long) read); +		DBG(18, "%s: read %lu bytes, status: %d\n", __func__, (unsigned long) read, status); -		if (read != buf_len + 1) -			return SANE_STATUS_IO_ERROR; +		if (status != SANE_STATUS_GOOD) { +			e2_cancel(s); +			return status; +		}  		if (e2_dev_model(dev, "GT-8200") || e2_dev_model(dev, "Perfection1650")) {  			/* See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=597922#127 */ diff --git a/backend/epson2.c b/backend/epson2.c index e023010..b1eda33 100644 --- a/backend/epson2.c +++ b/backend/epson2.c @@ -977,7 +977,7 @@ init_options(Epson_Scanner *s)  	s->opt[OPT_MODE].size = max_string_size(mode_list);  	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;  	s->opt[OPT_MODE].constraint.string_list = mode_list; -	s->val[OPT_MODE].w = 0;	/* Binary */ +	s->val[OPT_MODE].w = 0;	/* Lineart */  	/* disable infrared on unsupported scanners */  	if (!e2_model(s, "GT-X800") && !e2_model(s, "GT-X700") && !e2_model(s, "GT-X900")) @@ -988,14 +988,13 @@ init_options(Epson_Scanner *s)  	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].unit = SANE_UNIT_NONE; +	s->opt[OPT_BIT_DEPTH].unit = SANE_UNIT_BIT;  	s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;  	s->opt[OPT_BIT_DEPTH].constraint.word_list = s->hw->depth_list; -	s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; -	s->val[OPT_BIT_DEPTH].w = s->hw->depth_list[1];	/* the first "real" element is the default */ +	s->val[OPT_BIT_DEPTH].w = 8; /* default to 8 bit */ -	if (s->hw->depth_list[0] == 1)	/* only one element in the list -> hide the option */ -		s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; +	/* default is Lineart, disable depth selection */ +	s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;  	/* halftone */  	s->opt[OPT_HALFTONE].name = SANE_NAME_HALFTONE; @@ -1535,6 +1534,8 @@ sane_close(SANE_Handle handle)  	int i;  	Epson_Scanner *s; +	DBG(1, "* %s\n", __func__); +  	/*  	 * XXX Test if there is still data pending from  	 * the scanner. If so, then do a cancel @@ -1909,6 +1910,8 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info)  		sval->w = optindex; +		DBG(17, "%s: setting mode to %d\n", __func__, optindex); +  		/* halftoning available only on bw scans */  		if (s->hw->cmd->set_halftoning != 0)  			setOptionState(s, mode_params[optindex].depth == 1, @@ -1923,16 +1926,18 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info)  		/* if binary, then disable the bit depth selection */  		if (optindex == 0) { +			DBG(17, "%s: disabling bit depth selection\n", __func__);  			s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;  		} else { -			if (s->hw->depth_list[0] == 1) -				s->opt[OPT_BIT_DEPTH].cap |= -					SANE_CAP_INACTIVE; -			else { -				s->opt[OPT_BIT_DEPTH].cap &= -					~SANE_CAP_INACTIVE; -				s->val[OPT_BIT_DEPTH].w = -					mode_params[optindex].depth; +			if (s->hw->depth_list[0] == 1) { +				DBG(17, "%s: only one depth is available\n", __func__); +				s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; +			} else { + +				DBG(17, "%s: enabling bit depth selection\n", __func__); + +				s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE; +				s->val[OPT_BIT_DEPTH].w = mode_params[optindex].depth;  			}  		} @@ -2077,7 +2082,10 @@ sane_start(SANE_Handle handle)  	Epson_Device *dev = s->hw;  	SANE_Status status; -	DBG(5, "%s\n", __func__); +	DBG(5, "* %s\n", __func__); + +	s->eof = SANE_FALSE; +	s->canceling = SANE_FALSE;  	/* check if we just have finished working with the ADF */  	status = e2_check_adf(s); @@ -2202,9 +2210,7 @@ sane_start(SANE_Handle handle)  	if (s->buf == NULL)  		return SANE_STATUS_NO_MEM; -	s->eof = SANE_FALSE;  	s->ptr = s->end = s->buf; -	s->canceling = SANE_FALSE;  	/* feed the first sheet in the ADF */  	if (dev->ADF && dev->use_extension && dev->cmd->feed) { @@ -2275,8 +2281,14 @@ sane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length,  	SANE_Status status;  	Epson_Scanner *s = (Epson_Scanner *) handle; -	if (s->buf == NULL || s->canceling) -		return SANE_STATUS_CANCELLED; +	DBG(18, "* %s: eof: %d, canceling: %d\n", +		__func__, s->eof, s->canceling); + +	/* sane_read called before sane_start? */ +	if (s->buf == NULL) { +		DBG(1, "%s: buffer is NULL", __func__); +		return SANE_STATUS_INVAL; +	}  	*length = 0; @@ -2285,9 +2297,12 @@ sane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length,  	else  		status = e2_block_read(s); -	if (status == SANE_STATUS_CANCELLED) { +	/* The scanning operation might be canceled by the scanner itself +	 * or the fronted program +	 */ +	if (status == SANE_STATUS_CANCELLED || s->canceling) {  		e2_scan_finish(s); -		return status; +		return SANE_STATUS_CANCELLED;  	}  	/* XXX if FS G and STATUS_IOERR, use e2_check_extended_status */ @@ -2298,9 +2313,9 @@ sane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length,  	e2_copy_image_data(s, data, max_length, length); -	DBG(18, "%d lines read, eof: %d, status: %d\n", +	DBG(18, "%d lines read, eof: %d, canceling: %d, status: %d\n",  		*length / s->params.bytes_per_line, -		s->eof, status); +		s->canceling, s->eof, status);  	/* continue reading if appropriate */  	if (status == SANE_STATUS_GOOD) @@ -2323,6 +2338,8 @@ sane_cancel(SANE_Handle handle)  {  	Epson_Scanner *s = (Epson_Scanner *) handle; +	DBG(1, "* %s\n", __func__); +  	s->canceling = SANE_TRUE;  } diff --git a/backend/epson2.h b/backend/epson2.h index bb6c9e0..8650f01 100644 --- a/backend/epson2.h +++ b/backend/epson2.h @@ -346,7 +346,7 @@ struct Epson_Device  	SANE_Bool color_shuffle;	/* does this scanner need color shuffling */  	SANE_Int maxDepth;		/* max. color depth */ -	SANE_Word *depth_list; +	SANE_Int *depth_list;  	SANE_Int optical_res;		/* optical resolution */  	SANE_Int max_line_distance; diff --git a/backend/epsonds-cmd.c b/backend/epsonds-cmd.c new file mode 100644 index 0000000..5fb1f9d --- /dev/null +++ b/backend/epsonds-cmd.c @@ -0,0 +1,899 @@ +/* + * epsonds-cmd.c - Epson ESC/I-2 routines. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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" +#include <ctype.h> +#include <unistd.h>	     /* sleep */ + +#include "epsonds.h" +#include "epsonds-io.h" +#include "epsonds-cmd.h" +#include "epsonds-ops.h" + +static SANE_Status +esci2_parse_block(char *buf, int len, void *userdata, SANE_Status (*cb)(void *userdata, char *token, int len)) +{ +	SANE_Status status = SANE_STATUS_GOOD; +	SANE_Status delayed_status = SANE_STATUS_GOOD; + + +	char *start = buf; +	char *end = (buf + len) - 1; + +	/* 0  : # +	 * 1-3: param +	 * 4- : data +	*/ + +	while (1) { + +		char param[4]; + +		while (*start != '#' && start < end) +			start++; + +		if (*start != '#') +			break; + +		param[0] = *++start; +		param[1] = *++start; +		param[2] = *++start; +		param[3] = '\0'; + +		if (strncmp("---", param, 3) == 0) +			break; + +		/* ugly hack to skip over GMT in RESA */ +		if (strncmp("GMT", param, 3) == 0 && *(start + 5) == 'h') { +			start = start + 4 + 0x100; +			continue; +		} + +		/* find the end of the token */ +		{ +			int tlen; +			char *next = start; + +			while (*next != '#' && *next != 0x00 && next < end) +				next++; + +			tlen = next - start - 1; + +			if (cb) { +				status = cb(userdata, start - 2, tlen); +				if (status != SANE_STATUS_GOOD) { +					delayed_status = status; +				} +			} + +			start = next; +		} +	} + +	if (delayed_status != SANE_STATUS_GOOD) +		return delayed_status; + +	return status; +} + +static SANE_Bool +esci2_check_header(const char *cmd, const char *buf, unsigned int *more) +{ +	int err; + +	*more = 0; + +	if (strncmp(cmd, buf, 4) != 0) { + +		if (strncmp("UNKN", buf, 4) == 0) { +			DBG(1, "UNKN reply code received\n"); +		} else if (strncmp("INVD", buf, 4) == 0) { +			DBG(1, "INVD reply code received\n"); +		} else { +			DBG(1, "%c%c%c%c, unexpected reply code\n", buf[0], buf[1], buf[2], buf[3]); +		} + +		return 0; +	} + +	/* INFOx0000100#.... */ + +	/* read the answer len */ +	if (buf[4] != 'x') { +		DBG(1, "unknown type in header: %c\n", buf[4]); +		return 0; +	} + +	err = sscanf(&buf[5], "%x#", more); +	if (err != 1) { +		DBG(1, "cannot decode length from header\n"); +		return 0; +	} + +	return 1; +} + +static SANE_Status esci2_cmd(epsonds_scanner* s, +	char *cmd, size_t len, +	char *payload, size_t plen, +	void *userdata, SANE_Status (*cb)(void *userdata, char *token, int len)) +{ +	SANE_Status status; +	unsigned int more; +	char rbuf[64]; + +	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); +		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 (%d)\n", rbuf, plen); + +		eds_send(s, rbuf, 12, &status); + +	} else { +		eds_send(s, cmd, len, &status); +	} + +	if (status != SANE_STATUS_GOOD) { +		return status; +	} + +	/* send ParameterBlock */ +	if (payload && plen) { + +		eds_send(s, payload, plen, &status); +		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 +	 */ +	if (!esci2_check_header(cmd, rbuf, &more)) { +		return SANE_STATUS_IO_ERROR; +	} + +	/* parse the received header block */ +	if (cb) { +		status = esci2_parse_block(rbuf + 12, 64 - 12, userdata, cb); +		if (status != SANE_STATUS_GOOD && status != SANE_STATUS_DEVICE_BUSY) { +			DBG(1, "%s: %4s error while parsing received header\n", __func__, cmd); +		} +	} + +	/* header valid, get the data block if present */ +	if (more) { + +		char *pbuf = malloc(more); +		if (pbuf) { + +			ssize_t read = eds_recv(s, pbuf, more, &status); +			if (read != more) { +			} + +			/* parse the received data block */ +			if (cb) { +				status = esci2_parse_block(pbuf, more, userdata, cb); +				if (status != SANE_STATUS_GOOD) { +					DBG(1, "%s: %4s error while parsing received data block\n", __func__, cmd); +				} +			} + +			free(pbuf); + +		} else { +			return SANE_STATUS_NO_MEM; +		} +	} + +	return status; +} + +static SANE_Status esci2_cmd_simple(epsonds_scanner* s, char *cmd, SANE_Status (*cb)(void *userdata, char *token, int len)) +{ +	return esci2_cmd(s, cmd, 12, NULL, 0, s, cb); +} + +SANE_Status esci2_fin(epsonds_scanner *s) +{ +	DBG(5, "%s\n", __func__); + +	SANE_Status status = esci2_cmd_simple(s, "FIN x0000000", NULL); +	s->locked = 0; +	return status; +} + +SANE_Status esci2_can(epsonds_scanner *s) +{ +	return esci2_cmd_simple(s, "CAN x0000000", NULL); +} + +static int decode_value(char *buf, int len) +{ +	char tmp[10]; + +	memcpy(tmp, buf, len); +	tmp[len] = '\0'; + +	if (buf[0] == 'd' && len == 4) { +		return strtol(buf + 1, NULL, 10); +	} else if (buf[0] == 'i' && len == 8) { +		return strtol(buf + 1, NULL, 10); +	} else if (buf[0] == 'x' && len == 8) { +		return strtol(buf + 1, NULL, 16); +	} else if (buf[0] == 'h' && len == 4) { +		return strtol(buf + 1, NULL, 16); +	} + +	return -1; +} + +/* h000 */ +static char *decode_binary(char *buf) +{ +	char tmp[6]; + +	memcpy(tmp, buf, 4); +	tmp[4] = '\0'; + +	if (buf[0] != 'h') +		return NULL; + +	int hl = strtol(tmp + 1, NULL, 16); +	if (hl) { + +		char *v = malloc(hl + 1); +		memcpy(v, buf + 4, hl); +		v[hl] = '\0'; + +		return v; +	} + +	return NULL; +} + +static char *decode_string(char *buf) +{ +	char *s = decode_binary(buf); +	if (s == NULL) +		return NULL; + +	/* trim white space at the end */ +	char *p = s + strlen(s); +	while (*--p == ' ') +		*p = '\0'; + +	return s; +} + +static void debug_token(int level, const char *func, char *token, int len) +{ +	char *tdata = malloc(len + 1); +	memcpy(tdata, token + 3, len); +	tdata[len] = '\0'; + +	DBG(level, "%s: %3.3s / %s / %d\n", func, token, tdata, len); + +	free(tdata); +} + +static SANE_Status info_cb(void *userdata, char *token, int len) +{ +	epsonds_scanner *s = (epsonds_scanner *)userdata; + +	if (DBG_LEVEL >= 11) { +		debug_token(DBG_LEVEL, __func__, token, len); +	} + +	/* pointer to the token's value */ +	char *value = token + 3; + +	/* nrd / nrdBUSY */ + +	if (strncmp("nrd", token, 3) == 0) { +		if (strncmp("BUSY", value, 4) == 0) { +			return SANE_STATUS_DEVICE_BUSY; +		} +	} + +	if (strncmp("PRD", token, 3) == 0) { +		free(s->hw->model); +		s->hw->model = decode_string(value); +		s->hw->sane.model = s->hw->model; +		DBG(1, " product: %s\n", s->hw->model); +		/* we will free the string later */ +	} + +	if (strncmp("VER", token, 3) == 0) { +		char *v = decode_string(value); +		DBG(1, " version: %s\n", v); +		free(v); +	} + +	if (strncmp("S/N", token, 3) == 0) { +		char *v = decode_string(value); +		DBG(1, "  serial: %s\n", v); +		free(v); +	} + +	if (strncmp("ADF", token, 3) == 0) { + +		s->hw->has_adf = 1; + +		if (len == 8) { + +			if (strncmp("TYPEPAGE", value, len) == 0) { +				DBG(1, "     ADF: page type\n"); +			} + +			if (strncmp("TYPEFEED", value, len) == 0) { +				DBG(1, "     ADF: sheet feed type\n"); +			} + +			if (strncmp("DPLX1SCN", value, len) == 0) { +				DBG(1, "     ADF: duplex single pass\n"); +				s->hw->adf_singlepass = 1; +			} + +			if (strncmp("DPLX2SCN", value, len) == 0) { +				DBG(1, "     ADF: duplex double pass\n"); +				s->hw->adf_singlepass = 0; +			} + +			if (strncmp("FORDPF1N", value, len) == 0) { +				DBG(1, "     ADF: order is 1 to N\n"); +			} + +			if (strncmp("FORDPFN1", value, len) == 0) { +				DBG(1, "     ADF: order is N to 1\n"); +			} + +			if (strncmp("ALGNLEFT", value, len) == 0) { +				DBG(1, "     ADF: left aligned\n"); +				s->hw->adf_alignment = 0; +			} + +			if (strncmp("ALGNCNTR", value, len) == 0) { +				DBG(1, "     ADF: center aligned\n"); +				s->hw->adf_alignment = 1; +			} + +			if (strncmp("ALGNRIGT", value, len) == 0) { +				DBG(1, "     ADF: right aligned (not supported!)\n"); +				s->hw->adf_alignment = 2; +			} +		} + +		if (len == 4) { + +			if (strncmp("PREF", value, len) == 0) { +				DBG(1, "     ADF: auto pre-feed\n"); +			} + +			if (strncmp("ASCN", value, len) == 0) { +				DBG(1, "     ADF: auto scan\n"); +			} + +			if (strncmp("RCVR", value, len) == 0) { +				DBG(1, "     ADF: auto recovery\n"); +			} +		} + +		if (len == 20) { + +			/* ADFAREAi0000850i0001400 */ + +			if (strncmp("AREA", value, 4) == 0) { + +				int min = decode_value(value + 4, 8); +				int max = decode_value(value + 4 + 8, 8); + +				DBG(1, "     ADF: area %dx%d @ 100dpi\n", min, max); +			} + +			if (strncmp("AMIN", value, 4) == 0) { + +				int min = decode_value(value + 4, 8); +				int max = decode_value(value + 4 + 8, 8); + +				DBG(1, "     ADF: min %dx%d @ 100dpi\n", min, max); +			} + +			if (strncmp("AMAX", value, 4) == 0) { + +				int min = decode_value(value + 4, 8); +				int max = decode_value(value + 4 + 8, 8); + +				DBG(1, "     ADF: max %dx%d @ 100dpi\n", min, max); + +				eds_set_adf_area(s->hw,	min, max, 100); +			} +		} + +		if (len == 12) { + +			/* RESOi0000600 */ + +			if (strncmp("RESO", value, 4) == 0) { + +				int res = decode_value(value + 4, 8); + +				DBG(1, "     ADF: basic resolution is %d dpi\n", res); +			} + +			/* OVSNd025d035 */ + +			if (strncmp("OVSN", value, 4) == 0) { + +				int x = decode_value(value + 4, 4); +				int y = decode_value(value + 4 + 4, 4); + +				DBG(1, "     ADF: overscan %dx%d @ 100dpi\n", x, y); +			} +		} +	} + +	if (strncmp("FB ", token, 3) == 0) { + +		s->hw->has_fb = 1; + +		if (len == 20) { + +			/* AREAi0000850i0001400 */ +			if (strncmp("AREA", value, 4) == 0) { + +				int min = decode_value(value + 4, 8); +				int max = decode_value(value + 4 + 8, 8); + +				DBG(1, "      FB: area %dx%d @ 100dpi\n", min, max); + +				eds_set_fbf_area(s->hw,	min, max, 100); +			} +		} + +		if (len == 8) { + +			if (strncmp("ALGNLEFT", value, len) == 0) { +				DBG(1, "      FB: left aligned\n"); +				s->hw->fbf_alignment = 0; +			} + +			if (strncmp("ALGNCNTR", value, len) == 0) { +				DBG(1, "      FB: center aligned\n"); +				s->hw->fbf_alignment = 1; +			} + +			if (strncmp("ALGNRIGT", value, len) == 0) { +				DBG(1, "      FB: right aligned (not supported!)\n"); +				s->hw->fbf_alignment = 2; +			} +		} + +		if (len == 12) { + +			/* RESOi0000600 */ + +			if (strncmp("RESO", value, 4) == 0) { + +				int res = decode_value(value + 4, 8); + +				DBG(1, "      FB: basic resolution is %d dpi\n", res); +			} + +			/* OVSNd025d035 */ + +			if (strncmp("OVSN", value, 4) == 0) { + +				int x = decode_value(value + 4, 4); +				int y = decode_value(value + 4 + 4, 4); + +				DBG(1, "      FB: overscan %dx%d @ 100dpi\n", x, y); +			} +		} + +		if (len == 4) { + +			if (strncmp("DETX", value, len) == 0) { +				DBG(1, "      FB: paper width detection\n"); +			} + +			if (strncmp("DETY", value, len) == 0) { +				DBG(1, "      FB: paper height detection\n"); +			} +		} +	} + +	return SANE_STATUS_GOOD; +} + +SANE_Status esci2_info(epsonds_scanner *s) +{ +	DBG(1, "= gathering device information\n"); + +	SANE_Status status; +	int i = 4; + +	do { +		status = esci2_cmd_simple(s, "INFOx0000000", &info_cb); +		if (status == SANE_STATUS_DEVICE_BUSY) { +			sleep(2); +		} + +		i--; + +	} while (status == SANE_STATUS_DEVICE_BUSY && i); + +	return status; +} + +/* CAPA */ + +static SANE_Status capa_cb(void *userdata, char *token, int len) +{ +	epsonds_scanner *s = (epsonds_scanner *)userdata; + +	char *value = token + 3; + +	if (DBG_LEVEL >= 11) { +		debug_token(DBG_LEVEL, __func__, token, len); +	} + +	if (len == 4) { + +		if (strncmp("ADFDPLX", token, 3 + 4) == 0) { +			DBG(1, "     ADF: duplex\n"); +			s->hw->adf_is_duplex = 1; +		} + +		if (strncmp("ADFSKEW", token, 3 + 4) == 0) { +			DBG(1, "     ADF: skew correction\n"); +			s->hw->adf_has_skew = 1; +		} + +		if (strncmp("ADFOVSN", token, 3 + 4) == 0) { +			DBG(1, "     ADF: overscan\n"); +		} + +		if (strncmp("ADFPEDT", token, 3 + 4) == 0) { +			DBG(1, "     ADF: paper end detection\n"); +		} + +		if (strncmp("ADFLOAD", token, 3 + 4) == 0) { +			DBG(1, "     ADF: paper load\n"); +			s->hw->adf_has_load = 1; +		} + +		if (strncmp("ADFEJCT", token, 3 + 4) == 0) { +			DBG(1, "     ADF: paper eject\n"); +			s->hw->adf_has_eject = 1; +		} + +		if (strncmp("ADFCRP ", token, 3 + 4) == 0) { +			DBG(1, "     ADF: image cropping\n"); +		} + +		if (strncmp("ADFFAST", token, 3 + 4) == 0) { +			DBG(1, "     ADF: fast mode available\n"); +		} + +		if (strncmp("ADFDFL1", token, 3 + 4) == 0) { +			DBG(1, "     ADF: double feed detection\n"); +		} +	} + +	if (len == 8 && strncmp("ADFDFL1DFL2", token, 3 + 4) == 0) { +		DBG(1, "     ADF: double feed detection (high sensitivity)\n"); +	} + +	if (strncmp("FMT", token, 3) == 0) { + +		/* a bit ugly... */ + +		if (len >= 8) { +			if (strncmp("RAW ", value + 4, 4) == 0) { +				s->hw->has_raw = 1; +			} +		} + +		if (len >= 12) { +			if (strncmp("RAW ", value + 8, 4) == 0) { +				s->hw->has_raw = 1; +			} +		} +	} + +	/* RSMRANGi0000050i0000600 */ + +	if (strncmp("RSMRANG", token, 3 + 4) == 0) { + +		char *p = token + 3 + 4; + +		if (p[0] == 'i') { + +			int min = decode_value(p, 8); +			int max = decode_value(p + 8, 8); + +			eds_set_resolution_range(s->hw, min, max); + +			DBG(1, "resolution min/max %d/%d\n", min, max); +		} +	} + +	/* RSMLISTi0000300i0000600 */ + +	if (strncmp("RSMLIST", token, 3 + 4) == 0) { + +		char *p = token + 3 + 4; + +		if (p[0] == 'i') { + +			int i; +			int count = (len - 4) / 8; + +			for (i = 0; i < count; i++) { + +				eds_add_resolution(s->hw, decode_value(p, 8)); +				p += 8; +			} +		} +	} + +	return SANE_STATUS_GOOD; +} + +SANE_Status esci2_capa(epsonds_scanner *s) +{ +	return esci2_cmd_simple(s, "CAPAx0000000", &capa_cb); +} + +/* STAT */ + +static SANE_Status stat_cb(void *userdata, char *token, int len) +{ +/* +	epsonds_scanner *s = (epsonds_scanner *)userdata; +	char *value = token + 3; +*/ +	userdata = userdata; + +	if (DBG_LEVEL >= 11) { +		debug_token(DBG_LEVEL, __func__, token, len); +	} + +	return SANE_STATUS_GOOD; +} + +SANE_Status esci2_stat(epsonds_scanner *s) +{ +	return esci2_cmd_simple(s, "STATx0000000", &stat_cb); +} + +/* RESA */ + +static SANE_Status resa_cb(void *userdata, char *token, int len) +{ +	/* epsonds_scanner *s = (epsonds_scanner *)userdata; */ + +	userdata = userdata; + +	if (DBG_LEVEL >= 11) { +		debug_token(DBG_LEVEL, __func__, token, len); +	} + +	return SANE_STATUS_GOOD; +} + +SANE_Status esci2_resa(epsonds_scanner *s) +{ +	return esci2_cmd_simple(s, "RESAx0000000", &resa_cb); +} + +/* PARA */ + +static SANE_Status para_cb(void *userdata, char *token, int len) +{ +	if (DBG_LEVEL >= 11) { +		debug_token(DBG_LEVEL, __func__, token, len); +	} + +	userdata = userdata; + +	if (strncmp("par", token, 3) == 0) { +		if (strncmp("FAIL", token + 3, 4) == 0) { +			DBG(1, "%s: parameter setting failed\n", __func__); +			return SANE_STATUS_INVAL; +		} +	} + +	return SANE_STATUS_GOOD; +} + +SANE_Status esci2_para(epsonds_scanner *s, char *parameters) +{ +	DBG(8, "%s: %s\n", __func__, parameters); +	return esci2_cmd(s, "PARAx0000000", 12, parameters, strlen(parameters), NULL, ¶_cb); +} + +SANE_Status esci2_mech(epsonds_scanner *s, char *parameters) +{ +	DBG(8, "%s: %s\n", __func__, parameters); +	return esci2_cmd(s, "MECHx0000000", 12, parameters, strlen(parameters), NULL, ¶_cb); +} + +SANE_Status esci2_trdt(epsonds_scanner *s) +{ +	return esci2_cmd_simple(s, "TRDTx0000000", NULL); +} + + +static SANE_Status img_cb(void *userdata, char *token, int len) +{ +	struct epsonds_scanner *s = userdata; + +	if (DBG_LEVEL >= 11) { +		debug_token(DBG_LEVEL, __func__, token, len); +	} + +	/* psti0000256i0000000i0000945 / 24 */ + +	/* integer comparison first so it's faster */ +	if (len == 24 && strncmp("pst", token, 3) == 0) { + +		s->dummy = decode_value(token + 3 + 8, 8); + +		DBG(10, "%s: pst width: %d, height: %d, dummy: %d\n", +			__func__, +			decode_value(token + 3, 8), +			decode_value(token + 3 + 8 + 8, 8), +			s->dummy); + +		return SANE_STATUS_GOOD; +	} + +	if (len == 16 && strncmp("pen", token, 3) == 0) { +		DBG(10, "%s: page end\n", __func__); +		s->eof = 1; +		return SANE_STATUS_EOF; +	} + +	/* typIMGA or typIMGB */ +	if (len == 4 && strncmp("typ", token, 3) == 0) { + +		if (token[6] == 'B') +			s->backside = 1; +		else +			s->backside = 0; + +		return SANE_STATUS_GOOD; +	} + +	if (strncmp("err", token, 3) == 0) { + +		s->scanning = 0; + +		char *option = token + 3;	/* ADF, TPU, FB */ +		char *cause = token + 3 + 4;	/* OPN, PJ, PE, ERR, LTF, LOCK, DFED, DTCL, AUT, PERM */ + +		DBG(1, "%s: error on option %3.3s, cause %4.4s\n", +			__func__, option, cause); + +		if (cause[0] == 'P' && cause[1] == 'J') +			return SANE_STATUS_JAMMED; + +		if (cause[0] == 'P' && cause[1] == 'E') +			return SANE_STATUS_NO_DOCS; + +		if (cause[0] == 'O' && cause[1] == 'P' && cause[2] == 'N') +			return SANE_STATUS_COVER_OPEN; + +		return SANE_STATUS_IO_ERROR; +	} + +	if (len == 4 && strncmp("atnCAN ", token, 3 + 4) == 0) { +		DBG(1, "%s: cancel request\n", __func__); +		s->canceling = 1; +		s->scanning = 0; +		return SANE_STATUS_CANCELLED; +	} + +	if (len == 4 && strncmp("lftd000", token, 3 + 4) == 0) { +		s->scanning = 0; +	} + +	return SANE_STATUS_GOOD; +} + + +SANE_Status +esci2_img(struct epsonds_scanner *s, SANE_Int *length) +{ +	SANE_Status status = SANE_STATUS_GOOD; + +	*length = 0; + +	if (s->canceling) +		return SANE_STATUS_CANCELLED; + +	/* request image data */ +	eds_send(s, "IMG x0000000", 12, &status); +	if (status != SANE_STATUS_GOOD) { +		return status; +	} + +	/* receive DataHeaderBlock */ +	memset(s->buf, 0x00, 64); +	eds_recv(s, s->buf, 64, &status); +	if (status != SANE_STATUS_GOOD) { +		return status; +	} + +	/* check if we need to read any image data */ +	unsigned int more = 0; +	if (!esci2_check_header("IMG ", (char *)s->buf, &more)) { +		return SANE_STATUS_IO_ERROR; +	} + +	/* this handles eof and errors */ +	SANE_Status parse_status = esci2_parse_block((char *)s->buf + 12, 64 - 12, s, &img_cb); + +	/* no more data? return using the status of the esci2_parse_block +	 * call, which might hold other error conditions. +	 */ +	if (!more) { +		return parse_status; +	} + +	/* ALWAYS read image data */ +	ssize_t read = eds_recv(s, s->buf, more, &status); +	if (status != SANE_STATUS_GOOD) { +		return status; +	} + +	if (read != more) { +		return SANE_STATUS_IO_ERROR; +	} + +	/* handle esci2_parse_block errors */ +	if (parse_status != SANE_STATUS_GOOD) { +		return parse_status; +	} + +	DBG(15, "%s: read %lu bytes, status: %d\n", __func__, (unsigned long) read, status); + +	*length = read; + +	if (s->canceling) { +		return SANE_STATUS_CANCELLED; +	} + +	return SANE_STATUS_GOOD; +} diff --git a/backend/epsonds-cmd.h b/backend/epsonds-cmd.h new file mode 100644 index 0000000..923e811 --- /dev/null +++ b/backend/epsonds-cmd.h @@ -0,0 +1,29 @@ +/* + * epsonds-cmd.h - Epson ESC/I-2 routines. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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. + */ + +#ifndef epsonds_cmd_h +#define epsonds_cmd_h + +SANE_Status esci2_info(epsonds_scanner *s); +SANE_Status esci2_fin(epsonds_scanner *s); +SANE_Status esci2_can(epsonds_scanner *s); +SANE_Status esci2_capa(epsonds_scanner *s); +SANE_Status esci2_resa(epsonds_scanner *s); +SANE_Status esci2_stat(epsonds_scanner *s); +SANE_Status esci2_para(epsonds_scanner *s, char *parameters); +SANE_Status esci2_mech(epsonds_scanner *s, char *parameters); +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 new file mode 100644 index 0000000..28bacfc --- /dev/null +++ b/backend/epsonds-io.c @@ -0,0 +1,177 @@ +/* + * epsonds-io.c - Epson ESC/I-2 driver, low level I/O. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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" +#include <ctype.h> +#include <unistd.h>     /* sleep */ + +#include "epsonds.h" +#include "epsonds-io.h" + +size_t eds_send(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status) +{ +	DBG(32, "%s: size = %lu\n", __func__, (u_long) length); + +	if (length == 2) { + +		char *cmd = buf; + +		switch (cmd[0]) { +		case FS: +			DBG(9, "%s: FS %c\n", __func__, cmd[1]); +			break; +		} +	} + +	if (s->hw->connection == SANE_EPSONDS_NET) { +		/* XXX */ +	} else if (s->hw->connection == SANE_EPSONDS_USB) { + +		size_t n = length; + +		*status = sanei_usb_write_bulk(s->fd, buf, &n); + +		return n; +	} + +	/* never reached */ + +	*status = SANE_STATUS_INVAL; + +	return 0; +} + +size_t eds_recv(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status) +{ +	size_t n = 0; + +	DBG(30, "%s: size = %ld, buf = %p\n", __func__, (long) length, buf); + +	if (s->hw->connection == SANE_EPSONDS_NET) { +		/* XXX */ +	} 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 < length) { +		DBG(1, "%s: expected = %lu, got = %ld, canceling: %d\n", __func__, +		    (u_long)length, (long)n, s->canceling); + +		*status = SANE_STATUS_IO_ERROR; +	} + +	return n; +} + +/* Simple function to exchange a fixed amount of data with the scanner */ + +SANE_Status eds_txrx(epsonds_scanner* s, char *txbuf, size_t txlen, +	    char *rxbuf, size_t rxlen) +{ +	SANE_Status status; +	size_t done; + +	done = eds_send(s, txbuf, txlen, &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; +	} + +	done = eds_recv(s, rxbuf, rxlen, &status); +	if (status != SANE_STATUS_GOOD) { +		DBG(1, "%s: rx err, %s\n", __func__, sane_strstatus(status)); +	} + +	return status; +} + +/* This function should be used to send codes that only requires the scanner + * to give back an ACK or a NAK, namely FS X or FS Y + */ + +SANE_Status eds_control(epsonds_scanner *s, void *buf, size_t buf_size) +{ +	char result; +	SANE_Status status; + +	DBG(12, "%s: size = %lu\n", __func__, (u_long) buf_size); + +	status = eds_txrx(s, buf, buf_size, &result, 1); +	if (status != SANE_STATUS_GOOD) { +		DBG(1, "%s: failed, %s\n", __func__, sane_strstatus(status)); +		return status; +	} + +	if (result == ACK) +		return SANE_STATUS_GOOD; + +	if (result == NAK) { +		DBG(3, "%s: NAK\n", __func__); +		return SANE_STATUS_INVAL; +	} + +	DBG(1, "%s: result is neither ACK nor NAK but 0x%02x\n", +		__func__, result); + +	return SANE_STATUS_INVAL; +} + +SANE_Status eds_fsy(epsonds_scanner *s) +{ +	return eds_control(s, "\x1CY", 2); +} + +SANE_Status eds_fsx(epsonds_scanner *s) +{ +	SANE_Status status = eds_control(s, "\x1CX", 2); +	if (status == SANE_STATUS_GOOD) { +		s->locked = 1; +	} + +	return status; +} + +SANE_Status eds_lock(epsonds_scanner *s) +{ +	SANE_Status status; + +	DBG(5, "%s\n", __func__); + +	if (s->hw->connection == SANE_EPSONDS_USB) { +		sanei_usb_set_timeout(USB_SHORT_TIMEOUT); +	} + +	status = eds_fsx(s); + +	if (s->hw->connection == SANE_EPSONDS_USB) { +		sanei_usb_set_timeout(USB_TIMEOUT); +	} + +	return status; +} + + diff --git a/backend/epsonds-io.h b/backend/epsonds-io.h new file mode 100644 index 0000000..1a1b2b7 --- /dev/null +++ b/backend/epsonds-io.h @@ -0,0 +1,33 @@ +/* + * epsonds-io.h - Epson ESC/I-2 driver, low level I/O. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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. + */ + +#ifndef epsonds_io_h +#define epsonds_io_h + +#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_recv(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status); + +SANE_Status eds_txrx(epsonds_scanner *s, char *txbuf, size_t txlen, +	char *rxbuf, size_t rxlen); + +SANE_Status eds_control(epsonds_scanner *s, void *buf, size_t buf_size); + +SANE_Status eds_fsy(epsonds_scanner *s); +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 new file mode 100644 index 0000000..d825d99 --- /dev/null +++ b/backend/epsonds-jpeg.c @@ -0,0 +1,221 @@ +/* + * epsonds-jpeg.c - Epson ESC/I-2 driver, JPEG support. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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 <math.h> + +#include "epsonds.h" +#include "epsonds-jpeg.h" +#include "epsonds-ops.h" + +#define min(A,B) (((A)<(B)) ? (A) : (B)) + +typedef struct +{ +	struct jpeg_source_mgr pub; + +	epsonds_scanner *s; +	JOCTET *buffer; + +	SANE_Byte *linebuffer; +	SANE_Int linebuffer_size; +	SANE_Int linebuffer_index; +} +epsonds_src_mgr; + +METHODDEF(void) +jpeg_init_source(j_decompress_ptr UNUSEDARG cinfo) +{ +} + +METHODDEF(void) +jpeg_term_source(j_decompress_ptr UNUSEDARG cinfo) +{ +} + +METHODDEF(boolean) +jpeg_fill_input_buffer(j_decompress_ptr cinfo) +{ +	epsonds_src_mgr *src = (epsonds_src_mgr *)cinfo->src; + +	/* read from the scanner or the ring buffer */ + +	int avail = eds_ring_avail(src->s->current); +	if (avail == 0) { +		return FALSE; +	} + +	/* read from scanner if no data? */ +	int size = min(1024, avail); + +	eds_ring_read(src->s->current, src->buffer, size); + +	src->pub.next_input_byte = src->buffer; +	src->pub.bytes_in_buffer = size; + +	return TRUE; +} + +METHODDEF (void) +jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ +	epsonds_src_mgr *src = (epsonds_src_mgr *)cinfo->src; + +	if (num_bytes > 0) { + +		while (num_bytes > (long)src->pub.bytes_in_buffer) { +			num_bytes -= (long)src->pub.bytes_in_buffer; +			jpeg_fill_input_buffer(cinfo); +		} + +		src->pub.next_input_byte += (size_t) num_bytes; +		src->pub.bytes_in_buffer -= (size_t) num_bytes; +	} +} + +SANE_Status +eds_jpeg_start(epsonds_scanner *s) +{ +	epsonds_src_mgr *src; + +	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(epsonds_src_mgr)); + +	memset(s->jpeg_cinfo.src, 0x00, sizeof(epsonds_src_mgr)); + +	src = (epsonds_src_mgr *)s->jpeg_cinfo.src; +	src->s = s; + +	src->buffer = (JOCTET *)(*s->jpeg_cinfo.mem->alloc_small)((j_common_ptr)&s->jpeg_cinfo, +							JPOOL_PERMANENT, +							1024 * sizeof(JOCTET)); + +	src->pub.init_source = jpeg_init_source; +	src->pub.fill_input_buffer = jpeg_fill_input_buffer; +	src->pub.skip_input_data = jpeg_skip_input_data; +	src->pub.resync_to_restart = jpeg_resync_to_restart; +	src->pub.term_source = jpeg_term_source; +	src->pub.bytes_in_buffer = 0; +	src->pub.next_input_byte = NULL; + +	s->jpeg_header_seen = 0; + +	return SANE_STATUS_GOOD; +} + +SANE_Status +eds_jpeg_read_header(epsonds_scanner *s) +{ +	epsonds_src_mgr *src = (epsonds_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)) { + +			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); + +			int 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; +	} +} + +void +eds_jpeg_finish(epsonds_scanner *s) +{ +	jpeg_destroy_decompress(&s->jpeg_cinfo); +} + +void +eds_jpeg_read(SANE_Handle handle, SANE_Byte *data, +	   SANE_Int max_length, SANE_Int *length) +{ +	epsonds_scanner *s = handle; + +	*length = 0; + +	struct jpeg_decompress_struct cinfo = s->jpeg_cinfo; +	epsonds_src_mgr *src = (epsonds_src_mgr *)s->jpeg_cinfo.src; + +	/* 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 s->jdst->buffer +	 * only one line at time is supported +	 */ + +	int l = jpeg_read_scanlines(&cinfo, s->jdst->buffer, 1); +	if (l == 0) { +		return; +	} + +	/* from s->jdst->buffer to linebuffer +	 * linebuffer holds width * bytesperpixel +	 */ + +	(*s->jdst->put_pixel_rows)(&cinfo, s->jdst, 1, (char *)src->linebuffer); + +	*length = cinfo.output_width * cinfo.output_components * 1; +	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; +} + + diff --git a/backend/epsonds-jpeg.h b/backend/epsonds-jpeg.h new file mode 100644 index 0000000..c54208e --- /dev/null +++ b/backend/epsonds-jpeg.h @@ -0,0 +1,19 @@ +/* + * epsonds.c - Epson ESC/I-2 driver, JPEG support. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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 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); +void eds_jpeg_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length, SANE_Int *length); diff --git a/backend/epsonds-ops.c b/backend/epsonds-ops.c new file mode 100644 index 0000000..94f1071 --- /dev/null +++ b/backend/epsonds-ops.c @@ -0,0 +1,474 @@ +/* + * epsonds-ops.c - Epson ESC/I-2 driver, support routines. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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" + +#include <unistd.h>		/* sleep */ +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#include "epsonds.h" +#include "epsonds-io.h" +#include "epsonds-ops.h" +#include "epsonds-cmd.h" + +extern struct mode_param mode_params[]; + +/* Define the different scan sources */ + +#define FBF_STR	SANE_I18N("Flatbed") +#define TPU_STR	SANE_I18N("Transparency Unit") +#define ADF_STR	SANE_I18N("Automatic Document Feeder") + +extern SANE_String_Const source_list[]; + +void +eds_dev_init(epsonds_device *dev) +{ +	dev->res_list = malloc(sizeof(SANE_Word)); +	dev->res_list[0] = 0; + +	dev->depth_list = malloc(sizeof(SANE_Word)); +	dev->depth_list[0] = 0; +} + +SANE_Status +eds_dev_post_init(struct epsonds_device *dev) +{ +	DBG(10, "%s\n", __func__); + +	SANE_String_Const *source_list_add = source_list; +	if (dev->has_fb) +		*source_list_add++ = FBF_STR; + +	if (dev->has_adf) +		*source_list_add++ = ADF_STR; + +	if (source_list[0] == 0 +		|| (dev->res_list[0] == 0 && dev->dpi_range.min == 0) +		|| dev->depth_list[0] == 0) { + +		DBG(1, "something is wrong in the discovery process, aborting.\n"); +		DBG(1, "sources: %ld, res: %d, depths: %d.\n", +			source_list_add - source_list, dev->res_list[0], dev->depth_list[0]); + +		return SANE_STATUS_INVAL; +	} + +	return SANE_STATUS_GOOD; +} + +SANE_Status +eds_add_resolution(epsonds_device *dev, int r) +{ +	DBG(10, "%s: add (dpi): %d\n", __func__, r); + +	/* first element is the list size */ +	dev->res_list[0]++; +	dev->res_list = realloc(dev->res_list, +						(dev->res_list[0] + 1) * +						sizeof(SANE_Word)); +	if (dev->res_list == NULL) +		return SANE_STATUS_NO_MEM; + +	dev->res_list[dev->res_list[0]] = r; + +	return SANE_STATUS_GOOD; +} + +SANE_Status +eds_set_resolution_range(epsonds_device *dev, int min, int max) +{ +	DBG(10, "%s: set min/max (dpi): %d/%d\n", __func__, min, max); + +	dev->dpi_range.min = min; +	dev->dpi_range.max = max; +	dev->dpi_range.quant = 1; + +	return SANE_STATUS_GOOD; +} + +void +eds_set_fbf_area(epsonds_device *dev, int x, int y, int unit) +{ +	if (x == 0 || y == 0) +		return; + +	dev->fbf_x_range.min = 0; +	dev->fbf_x_range.max = SANE_FIX(x * MM_PER_INCH / unit); +	dev->fbf_x_range.quant = 0; + +	dev->fbf_y_range.min = 0; +	dev->fbf_y_range.max = SANE_FIX(y * MM_PER_INCH / unit); +	dev->fbf_y_range.quant = 0; + +	DBG(5, "%s: %f,%f %f,%f %d [mm]\n", +	    __func__, +	    SANE_UNFIX(dev->fbf_x_range.min), +	    SANE_UNFIX(dev->fbf_y_range.min), +	    SANE_UNFIX(dev->fbf_x_range.max), +	    SANE_UNFIX(dev->fbf_y_range.max), unit); +} + +void +eds_set_adf_area(struct epsonds_device *dev, int x, int y, int unit) +{ +	dev->adf_x_range.min = 0; +	dev->adf_x_range.max = SANE_FIX(x * MM_PER_INCH / unit); +	dev->adf_x_range.quant = 0; + +	dev->adf_y_range.min = 0; +	dev->adf_y_range.max = SANE_FIX(y * MM_PER_INCH / unit); +	dev->adf_y_range.quant = 0; + +	DBG(5, "%s: %f,%f %f,%f %d [mm]\n", +	    __func__, +	    SANE_UNFIX(dev->adf_x_range.min), +	    SANE_UNFIX(dev->adf_y_range.min), +	    SANE_UNFIX(dev->adf_x_range.max), +	    SANE_UNFIX(dev->adf_y_range.max), unit); +} + +void +eds_set_tpu_area(struct epsonds_device *dev, int x, int y, int unit) +{ +	dev->tpu_x_range.min = 0; +	dev->tpu_x_range.max = SANE_FIX(x * MM_PER_INCH / unit); +	dev->tpu_x_range.quant = 0; + +	dev->tpu_y_range.min = 0; +	dev->tpu_y_range.max = SANE_FIX(y * MM_PER_INCH / unit); +	dev->tpu_y_range.quant = 0; + +	DBG(5, "%s: %f,%f %f,%f %d [mm]\n", +	    __func__, +	    SANE_UNFIX(dev->tpu_x_range.min), +	    SANE_UNFIX(dev->tpu_y_range.min), +	    SANE_UNFIX(dev->tpu_x_range.max), +	    SANE_UNFIX(dev->tpu_y_range.max), unit); +} + +SANE_Status +eds_add_depth(epsonds_device *dev, SANE_Word depth) +{ +	DBG(5, "%s: add (bpp): %d\n", __func__, depth); + +	/* > 8bpp not implemented yet */ +	if (depth > 8) { +		DBG(1, " not supported"); +		return SANE_STATUS_GOOD; +	} + +	if (depth > dev->max_depth) +		dev->max_depth = depth; + +	/* first element is the list size */ +	dev->depth_list[0]++; +	dev->depth_list = realloc(dev->depth_list, +						(dev->depth_list[0] + 1) * +						sizeof(SANE_Word)); + +	if (dev->depth_list == NULL) +		return SANE_STATUS_NO_MEM; + +	dev->depth_list[dev->depth_list[0]] = depth; + +	return SANE_STATUS_GOOD; +} + +SANE_Status +eds_init_parameters(epsonds_scanner *s) +{ +	int dpi, bytes_per_pixel; + +	memset(&s->params, 0, sizeof(SANE_Parameters)); + +	s->dummy = 0; + +	dpi = s->val[OPT_RESOLUTION].w; + +	if (SANE_UNFIX(s->val[OPT_BR_Y].w) == 0 || +		SANE_UNFIX(s->val[OPT_BR_X].w) == 0) +		return SANE_STATUS_INVAL; + +	s->left = ((SANE_UNFIX(s->val[OPT_TL_X].w) / MM_PER_INCH) * +		s->val[OPT_RESOLUTION].w) + 0.5; + +	s->top = ((SANE_UNFIX(s->val[OPT_TL_Y].w) / MM_PER_INCH) * +		s->val[OPT_RESOLUTION].w) + 0.5; + +	s->params.pixels_per_line = +		((SANE_UNFIX(s->val[OPT_BR_X].w - +			   s->val[OPT_TL_X].w) / MM_PER_INCH) * dpi) + 0.5; +	s->params.lines = +		((SANE_UNFIX(s->val[OPT_BR_Y].w - +			   s->val[OPT_TL_Y].w) / MM_PER_INCH) * dpi) + 0.5; + +	DBG(5, "%s: tlx %f tly %f brx %f bry %f [mm]\n", +	    __func__, +	    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)); + +	DBG(5, "%s: tlx %d tly %d brx %d bry %d [dots @ %d dpi]\n", +		__func__, s->left, s->top, +		s->params.pixels_per_line, s->params.lines, dpi); + +	/* center aligned? */ +	if (s->hw->alignment == 1) { + +		SANE_Int offset = ((SANE_UNFIX(s->hw->x_range->max) / MM_PER_INCH) * dpi) + 0.5; + +		s->left += ((offset - s->params.pixels_per_line) / 2); + +		DBG(5, "%s: centered to tlx %d tly %d brx %d bry %d [dots @ %d dpi]\n", +			__func__, s->left, s->top, +			s->params.pixels_per_line, s->params.lines, dpi); +	} + +	/* +	 * Calculate bytes_per_pixel and bytes_per_line for +	 * any color depths. +	 * +	 * 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 ... */ +		bytes_per_pixel++; +	} + +	/* pixels_per_line is rounded to the next 8bit boundary */ +	s->params.pixels_per_line = s->params.pixels_per_line & ~7; + +	s->params.last_frame = SANE_TRUE; + +	switch (s->val[OPT_MODE].w) { +	case MODE_BINARY: +	case MODE_GRAY: +		s->params.format = SANE_FRAME_GRAY; +		s->params.bytes_per_line = +			s->params.pixels_per_line * s->params.depth / 8; +		break; +	case MODE_COLOR: +		s->params.format = SANE_FRAME_RGB; +		s->params.bytes_per_line = +			3 * s->params.pixels_per_line * bytes_per_pixel; +		break; +	} + +	if (s->params.bytes_per_line == 0) { +		DBG(1, "bytes_per_line is ZERO\n"); +		return SANE_STATUS_INVAL; +	} + +	/* +	 * If (s->top + s->params.lines) is larger than the max scan area, reset +	 * the number of scan lines: +	 * XXX: precalculate the maximum scanning area elsewhere (use dev max_y) +	 */ + +	if (SANE_UNFIX(s->val[OPT_BR_Y].w) / MM_PER_INCH * dpi < +	    (s->params.lines + s->top)) { +		s->params.lines = +			((int) SANE_UNFIX(s->val[OPT_BR_Y].w) / MM_PER_INCH * +			 dpi + 0.5) - s->top; +	} + +	if (s->params.lines <= 0) { +		DBG(1, "wrong number of lines: %d\n", s->params.lines); +		return SANE_STATUS_INVAL; +	} + +	return SANE_STATUS_GOOD; +} + +void +eds_copy_image_from_ring(epsonds_scanner *s, SANE_Byte *data, SANE_Int max_length, +                   SANE_Int *length) +{ +	int lines, available; +	int hw_line_size = (s->params.bytes_per_line + s->dummy); + +	/* trim max_length to a multiple of hw_line_size */ +	max_length -= (max_length % hw_line_size); + +	/* check available data */ +	available = eds_ring_avail(s->current); +	if (max_length > available) +		max_length = available; + +	lines = max_length / hw_line_size; + +	DBG(18, "copying %d lines (%d, %d)\n", lines, s->params.bytes_per_line, s->dummy); + +	/* need more data? */ +	if (lines == 0) { +		*length = 0; +		return; +	} + +	*length = (lines * s->params.bytes_per_line); + +	/* we need to copy one line at time, skipping +	 * dummy bytes at the end of each line +	 */ + +	/* lineart */ +	if (s->params.depth == 1) { + +		while (lines--) { + +			eds_ring_read(s->current, s->line_buffer, s->params.bytes_per_line); +			eds_ring_skip(s->current, s->dummy); + +			int i; + +			SANE_Byte *p = s->line_buffer; + +			for (i = 0; i < s->params.bytes_per_line; i++) { +				*data++ = ~*p++; +			} +		} + +	} else { /* gray and color */ + +		while (lines--) { + +			eds_ring_read(s->current, data, s->params.bytes_per_line); +			eds_ring_skip(s->current, s->dummy); + +			data += s->params.bytes_per_line; + +		} +	} +} + +SANE_Status eds_ring_init(ring_buffer *ring, SANE_Int size) +{ +	ring->ring = realloc(ring->ring, size); +	if (!ring->ring) { +		return SANE_STATUS_NO_MEM; +	} + +	ring->size = size; +	ring->fill = 0; +	ring->end = ring->ring + size; +	ring->wp = ring->rp = ring->ring; + +	return SANE_STATUS_GOOD; +} + +SANE_Status eds_ring_write(ring_buffer *ring, SANE_Byte *buf, SANE_Int size) +{ +	if (size > (ring->size - ring->fill)) { +		DBG(1, "ring buffer full, requested: %d, available: %d\n", size, ring->size - ring->fill); +		return SANE_STATUS_NO_MEM; +	} + +	SANE_Int tail = ring->end - ring->wp; +	if (size < tail) { + +		memcpy(ring->wp, buf, size); + +		ring->wp += size; +		ring->fill += size; + +	} else { + +		memcpy(ring->wp, buf, tail); +		size -= tail; + +		ring->wp = ring->ring; +		memcpy(ring->wp, buf + tail, size); + +		ring->wp += size; +		ring->fill += (tail + size); +	} + +	return SANE_STATUS_GOOD; +} + +SANE_Int eds_ring_read(ring_buffer *ring, SANE_Byte *buf, SANE_Int size) +{ +	DBG(18, "reading from ring, %d bytes available\n", (int)ring->fill); + +	/* limit read to available */ +	if (size > ring->fill) { +		DBG(1, "not enough data in the ring, shouldn't happen\n"); +		size = ring->fill; +	} + +	SANE_Int tail = ring->end - ring->rp; +	if (size < tail) { + +		memcpy(buf, ring->rp, size); + +		ring->rp += size; +		ring->fill -= size; + +		return size; + +	} else { + +		memcpy(buf, ring->rp, tail); +		size -= tail; + +		ring->rp = ring->ring; +		memcpy(buf + tail, ring->rp, size); + +		ring->rp += size; +		ring->fill -= (size + tail); + +		return size + tail; +	} +} + +SANE_Int eds_ring_skip(ring_buffer *ring, SANE_Int size) +{ +	/* limit skip to available */ +	if (size > ring->fill) +		size = ring->fill; + +	SANE_Int tail = ring->end - ring->rp; +	if (size < tail) { +		ring->rp += size; +	} else { + +		ring->rp = ring->ring + (size - tail); +	} + +	ring->fill -= size; + +	return size; +} + +SANE_Int eds_ring_avail(ring_buffer *ring) +{ +	return ring->fill; +} + +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 new file mode 100644 index 0000000..3f45393 --- /dev/null +++ b/backend/epsonds-ops.h @@ -0,0 +1,41 @@ +/* + * epsonds-ops.h - Epson ESC/I-2 driver. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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 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_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); +extern void eds_set_adf_area(epsonds_device *dev, int x, int y, int unit); +extern void eds_set_tpu_area(epsonds_device *dev, int x, int y, int unit); + +extern SANE_Status eds_add_depth(epsonds_device *dev, SANE_Word depth); +extern SANE_Status eds_discover_capabilities(epsonds_scanner *s); +extern SANE_Status eds_set_extended_scanning_parameters(epsonds_scanner *s); +extern SANE_Status eds_set_scanning_parameters(epsonds_scanner *s); +extern void eds_setup_block_mode(epsonds_scanner *s); +extern SANE_Status eds_init_parameters(epsonds_scanner *s); + +extern void eds_copy_image_from_ring(epsonds_scanner *s, SANE_Byte *data, SANE_Int max_length, +                   SANE_Int *length); + +extern SANE_Status eds_ring_init(ring_buffer *ring, SANE_Int size); +extern SANE_Status eds_ring_write(ring_buffer *ring, SANE_Byte *buf, SANE_Int size); +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-usb.c b/backend/epsonds-usb.c new file mode 100644 index 0000000..c7e514c --- /dev/null +++ b/backend/epsonds-usb.c @@ -0,0 +1,33 @@ +/* + * epsonds-usb.c - Epson ESC/I-2 driver, USB device list. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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. + */ + +#include "epsonds-usb.h" + +SANE_Word epsonds_usb_product_ids[] = { +	0x0145,		/* DS-5500, DS-6500, DS-7500 */ +	0x0146,		/* DS-50000, DS-60000, DS-70000 */ +	0x014c,		/* DS-510 */ +	0x014d,		/* DS-560 */ +	0x0150,		/* DS-40 */ +	0x0152,		/* DS-760, DS-860 */ +	0x0154,		/* DS-520 */ +	0x08bc,		/* PX-M7050 Series, WF-8510/8590 Series */ +	0x08cc,		/* PX-M7050FX Series, WF-R8590 Series */ +	0		/* last entry - this is used for devices that are specified +			   in the config file as "usb <vendor> <product>" */ +}; + +int epsonds_get_number_of_ids(void) +{ +	return sizeof (epsonds_usb_product_ids) / sizeof (SANE_Word); +} diff --git a/backend/epsonds-usb.h b/backend/epsonds-usb.h new file mode 100644 index 0000000..96c77b5 --- /dev/null +++ b/backend/epsonds-usb.h @@ -0,0 +1,24 @@ +/* + * epsonds-usb.h - Epson ESC/I-2 driver, USB device list. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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. + */ + +#include "sane/sane.h" + +#ifndef _EPSONDS_USB_H_ +#define _EPSONDS_USB_H_ + +#define SANE_EPSONDS_VENDOR_ID	(0x4b8) + +extern SANE_Word epsonds_usb_product_ids[]; +extern int epsonds_get_number_of_ids(void); + +#endif diff --git a/backend/epsonds.c b/backend/epsonds.c new file mode 100644 index 0000000..d16744f --- /dev/null +++ b/backend/epsonds.c @@ -0,0 +1,1434 @@ +/* + * epsonds.c - Epson ESC/I-2 driver. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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 EPSONDS_VERSION		1 +#define EPSONDS_REVISION	0 +#define EPSONDS_BUILD		35 + +/* debugging levels: + * + *	32	eds_send + *	30	eds_recv + *	20	sane_read and related + *	18	sane_read and related + *	17	setvalue, getvalue, control_option + *	16 + *	15	esci2_img + *	13	image_cb + *	12	eds_control + *	11	all received params + *	10	some received params + *	 9 + *	 8	esci2_xxx + *	 7	open/close/attach + *	 6	print_params + *	 5	basic functions + *	 3	JPEG decompressor + *	 1	scanner info and capabilities + *	 0	errors + */ + +#include "sane/config.h" + +#include <ctype.h> + +#include "sane/saneopts.h" +#include "sane/sanei_config.h" + +#include "epsonds.h" +#include "epsonds-usb.h" +#include "epsonds-io.h" +#include "epsonds-cmd.h" +#include "epsonds-ops.h" +#include "epsonds-jpeg.h" + +/* + * 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. + */ + +struct mode_param mode_params[] = { +	{0, 0x00, 0x30, 1}, +	{0, 0x00, 0x30, 8}, +	{1, 0x02, 0x00, 8}, +	{0, 0x00, 0x30, 1} +}; + +static SANE_String_Const mode_list[] = { +	SANE_VALUE_SCAN_MODE_LINEART, +	SANE_VALUE_SCAN_MODE_GRAY, +	SANE_VALUE_SCAN_MODE_COLOR, +	NULL +}; + +static const SANE_String_Const adf_mode_list[] = { +	SANE_I18N("Simplex"), +	SANE_I18N("Duplex"), +	NULL +}; + +/* Define the different scan sources */ + +#define FBF_STR	SANE_I18N("Flatbed") +#define ADF_STR	SANE_I18N("Automatic Document Feeder") + +/* order will be fixed: fb, adf, tpu */ +SANE_String_Const source_list[] = { +	NULL, +	NULL, +	NULL, +	NULL +}; + +/* + * List of pointers to devices - will be dynamically allocated depending + * on the number of devices found. + */ +static const SANE_Device **devlist; + +/* Some utility functions */ + +static size_t +max_string_size(const SANE_String_Const strings[]) +{ +	size_t size, max_size = 0; +	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 attach_one_usb(SANE_String_Const devname); + +static void +print_params(const SANE_Parameters params) +{ +	DBG(6, "params.format          = %d\n", params.format); +	DBG(6, "params.last_frame      = %d\n", params.last_frame); +	DBG(6, "params.bytes_per_line  = %d\n", params.bytes_per_line); +	DBG(6, "params.pixels_per_line = %d\n", params.pixels_per_line); +	DBG(6, "params.lines           = %d\n", params.lines); +	DBG(6, "params.depth           = %d\n", params.depth); +} + +static void +close_scanner(epsonds_scanner *s) +{ +	DBG(7, "%s: fd = %d\n", __func__, s->fd); + +	if (s->fd == -1) +		return; + +	if (s->locked) { +		DBG(7, " unlocking scanner\n"); +		esci2_fin(s); +	} + +	if (s->hw->connection == SANE_EPSONDS_USB) { +		sanei_usb_close(s->fd); +	} + +	free(s->front.ring); +	free(s->back.ring); +	free(s->line_buffer); +	free(s); + +	DBG(7, "%s: ZZZ\n", __func__); +} + +static SANE_Status +open_scanner(epsonds_scanner *s) +{ +	SANE_Status status = SANE_STATUS_INVAL; + +	DBG(7, "%s: %s\n", __func__, s->hw->sane.name); + +	if (s->fd != -1) { +		DBG(5, "scanner is already open: fd = %d\n", s->fd); +		return SANE_STATUS_GOOD;	/* no need to open the scanner */ +	} + +	if (s->hw->connection == SANE_EPSONDS_USB) { + +		status = sanei_usb_open(s->hw->sane.name, &s->fd); +		sanei_usb_set_timeout(USB_TIMEOUT); + +	} else { +		DBG(1, "unknown connection type: %d\n", s->hw->connection); +	} + +	if (status == SANE_STATUS_ACCESS_DENIED) { +		DBG(1, "please check that you have permissions on the device.\n"); +		DBG(1, "if this is a multi-function device with a printer,\n"); +		DBG(1, "disable any conflicting driver (like usblp).\n"); +	} + +	if (status != SANE_STATUS_GOOD) +		DBG(1, "%s open failed: %s\n", +			s->hw->sane.name, +			sane_strstatus(status)); +	else +		DBG(5, " opened correctly\n"); + +	return status; +} + +static SANE_Status +validate_usb(struct epsonds_scanner *s) +{ +	DBG(1, "%s\n", __func__); + +	SANE_Status status; +	int vendor, product; +	int i = 0, numIds; + +	SANE_Bool is_valid = SANE_FALSE; + +	/* if the sanei_usb_get_vendor_product call is not supported, +	 * then we just ignore this and rely on the user to config +	 * the correct device. +	 */ +	status = sanei_usb_get_vendor_product(s->fd, &vendor, &product); +	if (status != SANE_STATUS_GOOD) { +		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_EPSONDS_VENDOR_ID) { +		/* this is not a supported vendor ID */ +		DBG(1, "not an Epson device at %s (vendor id=0x%x)\n", +			s->hw->sane.name, vendor); +		return SANE_STATUS_INVAL; +	} + +	numIds = epsonds_get_number_of_ids(); + +	/* check all known product IDs to verify that we know +	   about the device */ +	while (i != numIds && !is_valid) { +		if (product == epsonds_usb_product_ids[i]) +			is_valid = SANE_TRUE; +		i++; +	} + +	if (is_valid == SANE_FALSE) { +		DBG(1, "the device at %s is not a supported (product id=0x%x)\n", +			s->hw->sane.name, product); +		return SANE_STATUS_INVAL; +	} + +	DBG(1, "found valid Epson ESC/I-2 scanner: 0x%x/0x%x at %s\n", +		vendor, product, s->hw->sane.name); + +	return SANE_STATUS_GOOD; +} + +static int num_devices;			/* number of scanners attached to backend */ +static epsonds_device *first_dev;	/* first EPSON scanner in list */ + +static struct epsonds_scanner * +scanner_create(struct epsonds_device *dev, SANE_Status *status) +{ +	struct epsonds_scanner *s; + +	s = malloc(sizeof(struct epsonds_scanner)); +	if (s == NULL) { +		*status = SANE_STATUS_NO_MEM; +		return NULL; +	} + +	/* clear verything */ +	memset(s, 0x00, sizeof(struct epsonds_scanner)); + +	s->fd = -1; +	s->hw = dev; + +	return s; +} + +static struct epsonds_scanner * +device_detect(const char *name, int type, SANE_Status *status) +{ +	struct epsonds_scanner *s; +	struct epsonds_device *dev; + +	DBG(1, "%s\n", __func__); + +	/* 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"); +			return scanner_create(dev, status); +		} +	} + +	/* not found, create new if valid */ +	if (type == SANE_EPSONDS_NODEV) { +		*status = SANE_STATUS_INVAL; +		return NULL; +	} + +	/* alloc and clear our device structure */ +	dev = malloc(sizeof(*dev)); +	if (!dev) { +		*status = SANE_STATUS_NO_MEM; +		return NULL; +	} +	memset(dev, 0x00, sizeof(struct epsonds_device)); + +	s = scanner_create(dev, status); +	if (s == NULL) +		return NULL; + +	dev->connection = type; +	dev->model = strdup("(undetermined)"); + +	dev->sane.name = name; +	dev->sane.vendor = "Epson"; +	dev->sane.model = dev->model; +	dev->sane.type = "ESC/I-2"; + +	*status = open_scanner(s); +	if (*status != SANE_STATUS_GOOD) { +		free(s); +		return NULL; +	} + +	if (dev->connection == SANE_EPSONDS_USB) { +		*status = validate_usb(s); +	} + +	if (*status != SANE_STATUS_GOOD) +		goto close; + +	eds_dev_init(dev); + +	/* lock scanner */ +	*status = eds_lock(s); +	if (*status != SANE_STATUS_GOOD) { +		goto close; +	} + +	/* discover capabilities */ +	*status = esci2_info(s); +	if (*status != SANE_STATUS_GOOD) +		goto close; + +	*status = esci2_capa(s); +	if (*status != SANE_STATUS_GOOD) +		goto close; + +	*status = esci2_resa(s); +	if (*status != SANE_STATUS_GOOD) +		goto close; + +	/* 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 */ +	if (s->hw->has_fb) { + +		dev->x_range = &dev->fbf_x_range; +		dev->y_range = &dev->fbf_y_range; +		dev->alignment = dev->fbf_alignment; + +	} else if (s->hw->has_adf) { + +		dev->x_range = &dev->adf_x_range; +		dev->y_range = &dev->adf_y_range; +		dev->alignment = dev->adf_alignment; + +	} else { +		DBG(0, "unable to lay on the flatbed or feed the feeder. is that a scanner??\n"); +	} + +	*status = eds_dev_post_init(dev); +	if (*status != SANE_STATUS_GOOD) +		goto close; + +	DBG(1, "scanner model: %s\n", dev->model); + +	/* add this scanner to the device list */ + +	num_devices++; +	dev->next = first_dev; +	first_dev = dev; + +	return s; + +close: +	DBG(1, " failed\n"); + +	close_scanner(s); +	return NULL; +} + + +static SANE_Status +attach(const char *name, int type) +{ +	SANE_Status status; + +	DBG(7, "%s: devname = %s, type = %d\n", __func__, name, type); + +	epsonds_scanner *s = device_detect(name, type, &status); +	if (s == NULL) +		return status; + +	close_scanner(s); +	return status; +} + +SANE_Status +attach_one_usb(const char *dev) +{ +	DBG(7, "%s: dev = %s\n", __func__, dev); +	return attach(dev, SANE_EPSONDS_USB); +} + +static SANE_Status +attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) +{ +	int vendor, product; + +	int len = strlen(line); + +	DBG(7, "%s: len = %d, line = %s\n", __func__, len, line); + +	if (sscanf(line, "usb %i %i", &vendor, &product) == 2) { + +		int numIds; + +		/* add the vendor and product IDs to the list of +		   known devices before we call the attach function */ + +		DBG(7, " user configured device\n"); + +		numIds = epsonds_get_number_of_ids(); +		if (vendor != 0x4b8) +			return SANE_STATUS_INVAL; /* this is not an EPSON device */ + +		/* add to last slot */ +		epsonds_usb_product_ids[numIds - 1] = product; +		sanei_usb_attach_matching_devices(line, attach_one_usb); + +	} else if (strncmp(line, "usb", 3) == 0 && len == 3) { + +		int i, numIds; + +		DBG(7, " probing usb devices\n"); + +		numIds = epsonds_get_number_of_ids(); + +		for (i = 0; i < numIds; i++) { +			sanei_usb_find_devices(0x4b8, +					epsonds_usb_product_ids[i], attach_one_usb); +		} +	} else { +		DBG(0, "unable to parse config line: %s\n", line); +	} + +	return SANE_STATUS_GOOD; +} + +static void +free_devices(void) +{ +	epsonds_device *dev, *next; + +	for (dev = first_dev; dev; dev = next) { +		next = dev->next; +		free(dev->name); +		free(dev->model); +		free(dev); +	} + +	free(devlist); +	first_dev = NULL; +} + +static void +probe_devices(void) +{ +	DBG(5, "%s\n", __func__); + +	free_devices(); +	sanei_configure_attach(EPSONDS_CONFIG_FILE, NULL, attach_one_config); +} + +/**** SANE API ****/ + +SANE_Status +sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize) +{ +	DBG_INIT(); +	DBG(2, "%s: " PACKAGE " " VERSION "\n", __func__); + +	DBG(1, "epsonds backend, version %i.%i.%i\n", +		EPSONDS_VERSION, EPSONDS_REVISION, EPSONDS_BUILD); + +	if (version_code != NULL) +		*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, V_MINOR, +					  EPSONDS_BUILD); + +	sanei_usb_init(); + +	return SANE_STATUS_GOOD; +} + +void +sane_exit(void) +{ +	DBG(5, "** %s\n", __func__); +	free_devices(); +} + +SANE_Status +sane_get_devices(const SANE_Device ***device_list, SANE_Bool __sane_unused__ local_only) +{ +	int i; +	epsonds_device *dev; + +	DBG(5, "** %s\n", __func__); + +	probe_devices(); + +	devlist = malloc((num_devices + 1) * sizeof(devlist[0])); +	if (!devlist) { +		DBG(1, "out of memory (line %d)\n", __LINE__); +		return SANE_STATUS_NO_MEM; +	} + +	DBG(5, "%s - results:\n", __func__); + +	for (i = 0, dev = first_dev; i < num_devices && dev; dev = dev->next, i++) { +		DBG(1, " %d (%d): %s\n", i, dev->connection, dev->model); +		devlist[i] = &dev->sane; +	} + +	devlist[i] = NULL; + +	*device_list = devlist; + +	return SANE_STATUS_GOOD; +} + +static SANE_Status +init_options(epsonds_scanner *s) +{ +	int i; + +	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->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; + +	/* "Scan 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].cap = 0; + +	/* 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].size = max_string_size(mode_list); +	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; +	s->opt[OPT_MODE].constraint.string_list = mode_list; +	s->val[OPT_MODE].w = 0;	/* Lineart */ + +	/* bit depth */ +	s->opt[OPT_DEPTH].name = SANE_NAME_BIT_DEPTH; +	s->opt[OPT_DEPTH].title = SANE_TITLE_BIT_DEPTH; +	s->opt[OPT_DEPTH].desc = SANE_DESC_BIT_DEPTH; +	s->opt[OPT_DEPTH].type = SANE_TYPE_INT; +	s->opt[OPT_DEPTH].unit = SANE_UNIT_BIT; +	s->opt[OPT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; +	s->opt[OPT_DEPTH].constraint.word_list = s->hw->depth_list; +	s->val[OPT_DEPTH].w = s->hw->depth_list[1];	/* the first "real" element is the default */ + +	/* default is Lineart, disable depth selection */ +	s->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE; + +	/* 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; + +	/* range */ +	if (s->hw->dpi_range.quant) { +		s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; +		s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range; +		s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min; +	} else { /* list */ +		s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; +		s->opt[OPT_RESOLUTION].constraint.word_list = s->hw->res_list; +		s->val[OPT_RESOLUTION].w = s->hw->res_list[1]; +	} + +	/* "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; + +	/* 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 = s->hw->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 = s->hw->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 = s->hw->x_range; +	s->val[OPT_BR_X].w = s->hw->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 = s->hw->y_range; +	s->val[OPT_BR_Y].w = s->hw->y_range->max; + +	/* "Optional equipment" group: */ +	s->opt[OPT_EQU_GROUP].title = SANE_I18N("Optional equipment"); +	s->opt[OPT_EQU_GROUP].desc = ""; +	s->opt[OPT_EQU_GROUP].type = SANE_TYPE_GROUP; +	s->opt[OPT_EQU_GROUP].cap = SANE_CAP_ADVANCED; + +	/* 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].size = max_string_size(source_list); +	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; + +	s->opt[OPT_EJECT].name = "eject"; +	s->opt[OPT_EJECT].title = SANE_I18N("Eject"); +	s->opt[OPT_EJECT].desc = SANE_I18N("Eject the sheet in the ADF"); +	s->opt[OPT_EJECT].type = SANE_TYPE_BUTTON; + +	if (!s->hw->adf_has_eject) +		s->opt[OPT_EJECT].cap |= SANE_CAP_INACTIVE; + +	s->opt[OPT_LOAD].name = "load"; +	s->opt[OPT_LOAD].title = SANE_I18N("Load"); +	s->opt[OPT_LOAD].desc = SANE_I18N("Load a sheet in the ADF"); +	s->opt[OPT_LOAD].type = SANE_TYPE_BUTTON; + +	if (!s->hw->adf_has_load) +		s->opt[OPT_LOAD].cap |= SANE_CAP_INACTIVE; + +	s->opt[OPT_ADF_MODE].name = "adf-mode"; +	s->opt[OPT_ADF_MODE].title = SANE_I18N("ADF Mode"); +	s->opt[OPT_ADF_MODE].desc = +		SANE_I18N("Selects the ADF mode (simplex/duplex)"); +	s->opt[OPT_ADF_MODE].type = SANE_TYPE_STRING; +	s->opt[OPT_ADF_MODE].size = max_string_size(adf_mode_list); +	s->opt[OPT_ADF_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; +	s->opt[OPT_ADF_MODE].constraint.string_list = adf_mode_list; +	s->val[OPT_ADF_MODE].w = 0; /* simplex */ + +	if (!s->hw->adf_is_duplex) +		s->opt[OPT_ADF_MODE].cap |= SANE_CAP_INACTIVE; + +	s->opt[OPT_ADF_SKEW].name = "adf-skew"; +	s->opt[OPT_ADF_SKEW].title = SANE_I18N("ADF Skew Correction"); +	s->opt[OPT_ADF_SKEW].desc = +		SANE_I18N("Enables ADF skew correction"); +	s->opt[OPT_ADF_SKEW].type = SANE_TYPE_BOOL; +	s->val[OPT_ADF_SKEW].w = 0; + +	if (!s->hw->adf_has_skew) +		s->opt[OPT_ADF_SKEW].cap |= SANE_CAP_INACTIVE; + +	return SANE_STATUS_GOOD; +} + +SANE_Status +sane_open(SANE_String_Const name, SANE_Handle *handle) +{ +	SANE_Status status; +	epsonds_scanner *s = NULL; + +	int l = strlen(name); + +	DBG(7, "** %s: name = %s\n", __func__, name); + +	/* probe if empty device name provided */ +	if (l == 0) { + +		probe_devices(); + +		if (first_dev == NULL) { +			DBG(1, "no devices detected\n"); +			return SANE_STATUS_INVAL; +		} + +		s = device_detect(first_dev->sane.name, first_dev->connection, +					&status); +		if (s == NULL) { +			DBG(1, "cannot open a perfectly valid device (%s)," +				" please report to the authors\n", name); +			return SANE_STATUS_INVAL; +		} + +	} else { + +		if (strncmp(name, "libusb:", 7) == 0) { +			s = device_detect(name, SANE_EPSONDS_USB, &status); +			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(); + +			s = device_detect(name, SANE_EPSONDS_NODEV, &status); +			if (s == NULL) { +				DBG(1, "invalid device name: %s\n", name); +				return SANE_STATUS_INVAL; +			} +		} +	} + +	/* s is always valid here */ + +	DBG(5, "%s: handle obtained\n", __func__); + +	init_options(s); + +	*handle = (SANE_Handle)s; + +	status = open_scanner(s); +	if (status != SANE_STATUS_GOOD) { +		free(s); +		return status; +	} + +	/* lock scanner if required */ +	if (!s->locked) { +		status = eds_lock(s); +	} + +	return status; +} + +void +sane_close(SANE_Handle handle) +{ +	epsonds_scanner *s = (epsonds_scanner *)handle; + +	DBG(1, "** %s\n", __func__); + +	close_scanner(s); +} + +const SANE_Option_Descriptor * +sane_get_option_descriptor(SANE_Handle handle, SANE_Int option) +{ +	epsonds_scanner *s = (epsonds_scanner *) handle; + +	if (option < 0 || option >= NUM_OPTIONS) +		return NULL; + +	return s->opt + option; +} + +static const SANE_String_Const * +search_string_list(const SANE_String_Const *list, SANE_String value) +{ +	while (*list != NULL && strcmp(value, *list) != 0) +		list++; + +	return ((*list == NULL) ? NULL : list); +} + +static void +activateOption(epsonds_scanner *s, SANE_Int option, SANE_Bool *change) +{ +	if (!SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) { +		s->opt[option].cap &= ~SANE_CAP_INACTIVE; +		*change = SANE_TRUE; +	} +} + +static void +deactivateOption(epsonds_scanner *s, SANE_Int option, SANE_Bool *change) +{ +	if (SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) { +		s->opt[option].cap |= SANE_CAP_INACTIVE; +		*change = SANE_TRUE; +	} +} + +/* + * Handles setting the source (flatbed, transparency adapter (TPU), + * or auto document feeder (ADF)). + * + * For newer scanners it also sets the focus according to the + * glass / TPU settings. + */ + +static void +change_source(epsonds_scanner *s, SANE_Int optindex, char *value) +{ +	int force_max = SANE_FALSE; +	SANE_Bool dummy; + +	DBG(1, "%s: optindex = %d, source = '%s'\n", __func__, optindex, +	    value); + +	s->val[OPT_SOURCE].w = optindex; + +	/* if current selected area is the maximum available, +	 * keep this setting on the new source. +	 */ +	if (s->val[OPT_TL_X].w == s->hw->x_range->min +	    && s->val[OPT_TL_Y].w == s->hw->y_range->min +	    && s->val[OPT_BR_X].w == s->hw->x_range->max +	    && s->val[OPT_BR_Y].w == s->hw->y_range->max) { +		force_max = SANE_TRUE; +	} + +	if (strcmp(ADF_STR, value) == 0) { + +		s->hw->x_range = &s->hw->adf_x_range; +		s->hw->y_range = &s->hw->adf_y_range; +		s->hw->alignment = s->hw->adf_alignment; + +		if (s->hw->adf_is_duplex) { +			activateOption(s, OPT_ADF_MODE, &dummy); +		} else { +			deactivateOption(s, OPT_ADF_MODE, &dummy); +			s->val[OPT_ADF_MODE].w = 0; +		} + +	} else if (strcmp(TPU_STR, value) == 0) { + +		s->hw->x_range = &s->hw->tpu_x_range; +		s->hw->y_range = &s->hw->tpu_y_range; + +		deactivateOption(s, OPT_ADF_MODE, &dummy); + +	} else { + +		/* neither ADF nor TPU active, assume FB */ +		s->hw->x_range = &s->hw->fbf_x_range; +		s->hw->y_range = &s->hw->fbf_y_range; +		s->hw->alignment = s->hw->fbf_alignment; +	} + +	s->opt[OPT_BR_X].constraint.range = s->hw->x_range; +	s->opt[OPT_BR_Y].constraint.range = s->hw->y_range; + +	if (s->val[OPT_TL_X].w < s->hw->x_range->min || force_max) +		s->val[OPT_TL_X].w = s->hw->x_range->min; + +	if (s->val[OPT_TL_Y].w < s->hw->y_range->min || force_max) +		s->val[OPT_TL_Y].w = s->hw->y_range->min; + +	if (s->val[OPT_BR_X].w > s->hw->x_range->max || force_max) +		s->val[OPT_BR_X].w = s->hw->x_range->max; + +	if (s->val[OPT_BR_Y].w > s->hw->y_range->max || force_max) +		s->val[OPT_BR_Y].w = s->hw->y_range->max; +} + +static SANE_Status +getvalue(SANE_Handle handle, SANE_Int option, void *value) +{ +	epsonds_scanner *s = (epsonds_scanner *)handle; +	SANE_Option_Descriptor *sopt = &(s->opt[option]); +	Option_Value *sval = &(s->val[option]); + +	DBG(17, "%s: option = %d\n", __func__, option); + +	switch (option) { + +	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_DEPTH: +	case OPT_ADF_SKEW: +		*((SANE_Word *) value) = sval->w; +		break; + +	case OPT_MODE: +	case OPT_ADF_MODE: +	case OPT_SOURCE: +		strcpy((char *) value, sopt->constraint.string_list[sval->w]); +		break; + +	default: +		return SANE_STATUS_INVAL; +	} + +	return SANE_STATUS_GOOD; +} + +static SANE_Status +setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) +{ +	epsonds_scanner *s = (epsonds_scanner *) handle; +	SANE_Option_Descriptor *sopt = &(s->opt[option]); +	Option_Value *sval = &(s->val[option]); + +	SANE_Status status; +	const SANE_String_Const *optval = NULL; +	int optindex = 0; +	SANE_Bool reload = SANE_FALSE; + +	DBG(17, "** %s: option = %d, value = %p\n", __func__, option, value); + +	status = sanei_constrain_value(sopt, value, info); +	if (status != SANE_STATUS_GOOD) +		return status; + +	if (info && value && (*info & SANE_INFO_INEXACT) +	    && sopt->type == SANE_TYPE_INT) +		DBG(17, " constrained val = %d\n", *(SANE_Word *) value); + +	if (sopt->constraint_type == SANE_CONSTRAINT_STRING_LIST) { +		optval = search_string_list(sopt->constraint.string_list, +					    (char *) value); +		if (optval == NULL) +			return SANE_STATUS_INVAL; +		optindex = optval - sopt->constraint.string_list; +	} + +	/* block faulty frontends */ +	if (sopt->cap & SANE_CAP_INACTIVE) { +		DBG(1, " tried to modify a disabled parameter"); +		return SANE_STATUS_INVAL; +	} + +	switch (option) { + +	case OPT_ADF_MODE: /* simple lists */ +		sval->w = optindex; +		break; + +	case OPT_ADF_SKEW: +	case OPT_RESOLUTION: +		sval->w = *((SANE_Word *) value); +		reload = SANE_TRUE; +		break; + +	case OPT_BR_X: +	case OPT_BR_Y: +		sval->w = *((SANE_Word *) value); +		if (SANE_UNFIX(sval->w) == 0) { +			DBG(17, " invalid br-x or br-y\n"); +			return SANE_STATUS_INVAL; +		} +		/* passthru */ +	case OPT_TL_X: +	case OPT_TL_Y: +		sval->w = *((SANE_Word *) value); +		if (NULL != info) +			*info |= SANE_INFO_RELOAD_PARAMS; +		break; + +	case OPT_SOURCE: +		change_source(s, optindex, (char *) value); +		reload = SANE_TRUE; +		break; + +	case OPT_MODE: +	{ +		/* use JPEG mode if RAW is not available when bpp > 1 */ +		if (optindex > 0 && !s->hw->has_raw) { +			s->mode_jpeg = 1; +		} else { +			s->mode_jpeg = 0; +		} + +		sval->w = optindex; + +		/* if binary, then disable the bit depth selection */ +		if (optindex == 0) { +			s->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE; +		} else { +			if (s->hw->depth_list[0] == 1) +				s->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE; +			else { +				s->opt[OPT_DEPTH].cap &= ~SANE_CAP_INACTIVE; +				s->val[OPT_DEPTH].w = +					mode_params[optindex].depth; +			} +		} + +		reload = SANE_TRUE; +		break; +	} + +	case OPT_DEPTH: +		sval->w = *((SANE_Word *) value); +		mode_params[s->val[OPT_MODE].w].depth = sval->w; +		reload = SANE_TRUE; +		break; + +	case OPT_LOAD: +		esci2_mech(s, "#ADFLOAD"); +		break; + +	case OPT_EJECT: +		esci2_mech(s, "#ADFEJCT"); +		break; + +	default: +		return SANE_STATUS_INVAL; +	} + +	if (reload && info != NULL) +		*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; + +	return SANE_STATUS_GOOD; +} + +SANE_Status +sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, +		    void *value, SANE_Int *info) +{ +	DBG(17, "** %s: action = %x, option = %d\n", __func__, action, option); + +	if (option < 0 || option >= NUM_OPTIONS) +		return SANE_STATUS_INVAL; + +	if (info != NULL) +		*info = 0; + +	switch (action) { +	case SANE_ACTION_GET_VALUE: +		return getvalue(handle, option, value); + +	case SANE_ACTION_SET_VALUE: +		return setvalue(handle, option, value, info); + +	default: +		return SANE_STATUS_INVAL; +	} + +	return SANE_STATUS_INVAL; +} + +SANE_Status +sane_get_parameters(SANE_Handle handle, SANE_Parameters *params) +{ +	epsonds_scanner *s = (epsonds_scanner *)handle; + +	DBG(5, "** %s\n", __func__); + +	if (params == NULL) +		DBG(1, "%s: params is NULL\n", __func__); + +	/* +	 * If sane_start was already called, then just retrieve the parameters +	 * from the scanner data structure +	 */ +	if (s->scanning) { +		DBG(5, "scan in progress, returning saved params structure\n"); +	} else { +		/* otherwise initialize the params structure */ +		eds_init_parameters(s); +	} + +	if (params != NULL) +		*params = s->params; + +	print_params(s->params); + +	return SANE_STATUS_GOOD; +} + +/* + * This function is part of the SANE API and gets called from the front end to + * start the scan process. + */ + +SANE_Status +sane_start(SANE_Handle handle) +{ +	epsonds_scanner *s = (epsonds_scanner *)handle; +	char buf[64]; +	SANE_Status status = 0; + +	s->pages++; + +	DBG(5, "** %s, pages = %d, scanning = %d, backside = %d, front fill: %d, back fill: %d\n", +		__func__, s->pages, s->scanning, s->backside, +		eds_ring_avail(&s->front), +		eds_ring_avail(&s->back)); + +	s->eof = 0; +	s->canceling = 0; + +	if ((s->pages % 2) == 1) { +		s->current = &s->front; +		eds_ring_flush(s->current); +	} else if (eds_ring_avail(&s->back)) { +		DBG(5, "back side\n"); +		s->current = &s->back; +	} + +	/* prepare the JPEG decompressor */ +	if (s->mode_jpeg) { +		status = eds_jpeg_start(s); +		if (status != SANE_STATUS_GOOD) { +			goto end; +	}	} + +	/* scan already in progress? (one pass adf) */ +	if (s->scanning) { +		DBG(5, " scan in progress, returning early\n"); +		return SANE_STATUS_GOOD; +	} + +	/* calc scanning parameters */ +	status = eds_init_parameters(s); +	if (status != SANE_STATUS_GOOD) { +		DBG(1, " parameters initialization failed\n"); +		return status; +	} + +	/* allocate line buffer */ +	s->line_buffer = realloc(s->line_buffer, s->params.bytes_per_line); +	if (s->line_buffer == NULL) +		return SANE_STATUS_NO_MEM; + +	/* ring buffer for front page, twice bsz */ +	/* XXX read value from scanner */ +	status = eds_ring_init(&s->front, (65536 * 4) * 2); +	if (status != SANE_STATUS_GOOD) { +		return status; +	} + +	/* transfer buffer, bsz */ +	/* XXX read value from scanner */ +	s->buf = realloc(s->buf, 65536 * 4); +	if (s->buf == NULL) +		return SANE_STATUS_NO_MEM; + +	print_params(s->params); + +	/* set scanning parameters */ + +	char cmd[100]; /* take care not to overflow */ + +	/* document source */ +	if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) { + +		sprintf(buf, "#ADF%s%s", +			s->val[OPT_ADF_MODE].w ? "DPLX" : "", +			s->val[OPT_ADF_SKEW].w ? "SKEW" : ""); + +	} else if (strcmp(source_list[s->val[OPT_SOURCE].w], FBF_STR) == 0) { + +		strcpy(buf, "#FB "); + +	} else { +		/* XXX */ +	} + +	strcpy(cmd, buf); + +	if (s->params.format == SANE_FRAME_GRAY) { +		sprintf(buf, "#COLM%03d", s->params.depth); +	} else if (s->params.format == SANE_FRAME_RGB) { +		sprintf(buf, "#COLC%03d", s->params.depth * 3); +	} + +	strcat(cmd, buf); + +	/* image transfer format */ +	if (!s->mode_jpeg) { +		if (s->params.depth > 1 || s->hw->has_raw) { +			strcat(cmd, "#FMTRAW "); +		} +	} else { +		strcat(cmd, "#FMTJPG #JPGd090"); +	} + +	/* resolution (RSMi not always supported) */ + +	if (s->val[OPT_RESOLUTION].w > 999) { +		sprintf(buf, "#RSMi%07d", s->val[OPT_RESOLUTION].w); +	} else { +		sprintf(buf, "#RSMd%03d", s->val[OPT_RESOLUTION].w); +	} + +	strcat(cmd, buf); + +	/* scanning area */ +	sprintf(buf, "#ACQi%07di%07di%07di%07d", +		s->left, s->top, s->params.pixels_per_line, s->params.lines); + +	strcat(cmd, buf); + +	status = esci2_para(s, cmd); +	if (status != SANE_STATUS_GOOD) { +		goto end; +	} + +	/* start scanning */ +	DBG(1, "%s: scanning...\n", __func__); + +	/* switch to data state */ +	status = esci2_trdt(s); +	if (status != SANE_STATUS_GOOD) { +		goto end; +	} + +	/* first page is page 1 */ +	s->pages = 1; +	s->scanning = 1; + +end: +	if (status != SANE_STATUS_GOOD) { +		DBG(1, "%s: start failed: %s\n", __func__, sane_strstatus(status)); +	} + +	return status; +} + +/* this moves data from our buffers to SANE */ + +SANE_Status +sane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length, +	  SANE_Int *length) +{ +	SANE_Int read = 0, tries = 3; +	SANE_Status status = 0; +	epsonds_scanner *s = (epsonds_scanner *)handle; + +	*length = read = 0; + +	DBG(20, "** %s: backside = %d\n", __func__, s->backside); + +	/* sane_read called before sane_start? */ +	if (s->current == NULL) { +		DBG(0, "%s: buffer is NULL", __func__); +		return SANE_STATUS_INVAL; +	} + +	/* anything in the buffer? pass it to the frontend */ +	SANE_Int available = eds_ring_avail(s->current); +	if (available) { + +		DBG(18, "reading from ring buffer, %d left\n", available); + +		if (s->mode_jpeg && !s->jpeg_header_seen) { + +			status = eds_jpeg_read_header(s); +			if (status != SANE_STATUS_GOOD && --tries) { +				goto read_again; +			} +		} + +		if (s->mode_jpeg) { +			eds_jpeg_read(handle, data, max_length, &read); +		} else { +			eds_copy_image_from_ring(s, data, max_length, &read); +		} + +		if (read == 0) { +			goto read_again; +		} + +		*length = read; + +		return SANE_STATUS_GOOD; + + +	} else if (s->current == &s->back) { + +		/* finished reading the back page, next +		 * command should give us the EOF +		 */ +		DBG(18, "back side ring buffer empty\n"); +	} + +	/* read until data or error */ + +read_again: + +	status = esci2_img(s, &read); +	if (status != SANE_STATUS_GOOD) { +		DBG(20, "read: %d, eof: %d, backside: %d, status: %d\n", read, s->eof, s->backside, status); +	} + +	/* just got a back side page, alloc ring buffer if necessary +	 * we didn't before because dummy was not known +	 */ +	if (s->backside) { + +		int required = s->params.lines * (s->params.bytes_per_line + s->dummy); + +		if (s->back.size < required) { + +			DBG(20, "allocating buffer for the back side\n"); + +			status = eds_ring_init(&s->back, required); +			if (status != SANE_STATUS_GOOD) { +				return status; +			} +		} +	} + +	/* abort scanning when appropriate */ +	if (status == SANE_STATUS_CANCELLED) { +		esci2_can(s); +		return status; +	} + +	if (s->eof && s->backside) { +		DBG(18, "back side scan finished\n"); +	} + +	/* read again if no error and no data */ +	if (read == 0 && status == SANE_STATUS_GOOD) { +		goto read_again; +	} + +	/* got something, write to ring */ +	if (read) { + +		DBG(20, " %d bytes read, %d lines, eof: %d, canceling: %d, status: %d, backside: %d\n", +			read, read / (s->params.bytes_per_line + s->dummy), +			s->canceling, s->eof, status, s->backside); + +		/* move data to the appropriate ring */ +		status = eds_ring_write(s->backside ? &s->back : &s->front, s->buf, read); + +		if (0 && s->mode_jpeg && !s->jpeg_header_seen +			&& status == SANE_STATUS_GOOD) { + +			status = eds_jpeg_read_header(s); +			if (status != SANE_STATUS_GOOD && --tries) { +				goto read_again; +			} +		} +	} + +	/* continue reading if appropriate */ +	if (status == SANE_STATUS_GOOD) +		return status; + +	/* cleanup */ +	DBG(5, "** %s: cleaning up\n", __func__); + +	if (s->mode_jpeg) { +		eds_jpeg_finish(s); +	} + +	eds_ring_flush(s->current); + +	return status; +} + +/* + * 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. + */ + +void +sane_cancel(SANE_Handle handle) +{ +	DBG(1, "** %s\n", __func__); +	((epsonds_scanner *)handle)->canceling = SANE_TRUE; +} + +/* + * SANE_Status sane_set_io_mode() + * + * not supported - for asynchronous I/O + */ + +SANE_Status +sane_set_io_mode(SANE_Handle __sane_unused__ handle, +	SANE_Bool __sane_unused__ non_blocking) +{ +	return SANE_STATUS_UNSUPPORTED; +} + +/* + * SANE_Status sane_get_select_fd() + * + * not supported - for asynchronous I/O + */ + +SANE_Status +sane_get_select_fd(SANE_Handle __sane_unused__ handle, +	SANE_Int __sane_unused__ *fd) +{ +	return SANE_STATUS_UNSUPPORTED; +} diff --git a/backend/epsonds.conf.in b/backend/epsonds.conf.in new file mode 100644 index 0000000..bd032f3 --- /dev/null +++ b/backend/epsonds.conf.in @@ -0,0 +1,12 @@ +# epsonds.conf +# +# here are some examples for how to configure the epsonds backend + +# USB +usb + +# For libusb support for unknown scanners use the following command +# usb <product ID> <device ID> +# e.g.: +# usb 0x4b8 0x14c + diff --git a/backend/epsonds.h b/backend/epsonds.h new file mode 100644 index 0000000..2c2e422 --- /dev/null +++ b/backend/epsonds.h @@ -0,0 +1,198 @@ +/* + * epsonds.c - Epson ESC/I-2 driver. + * + * Copyright (C) 2015 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * 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. + */ + +#ifndef epsonds_h +#define epsonds_h + +#undef BACKEND_NAME +#define BACKEND_NAME epsonds +#define DEBUG_NOT_STATIC + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_STDDEF_H +#include <stddef.h> +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef NEED_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include <string.h> /* for memset and memcpy */ +#include <stdio.h> + +#include "sane/sane.h" +#include "sane/sanei_backend.h" +#include "sane/sanei_debug.h" +#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 +#define PATH_MAX (1024) +#endif + +#ifndef XtNumber +#define XtNumber(x)  (sizeof(x) / sizeof(x[0])) +#define XtOffset(p_type, field)  ((size_t)&(((p_type)NULL)->field)) +#define XtOffsetOf(s_type, field)  XtOffset(s_type*, field) +#endif + +#define ACK	0x06 +#define NAK	0x15 +#define	FS	0x1C + +#define FBF_STR SANE_I18N("Flatbed") +#define TPU_STR SANE_I18N("Transparency Unit") +#define ADF_STR SANE_I18N("Automatic Document Feeder") + +enum { +	OPT_NUM_OPTS = 0, +	OPT_MODE_GROUP, +	OPT_MODE, +	OPT_DEPTH, +	OPT_RESOLUTION, +	OPT_GEOMETRY_GROUP, +	OPT_TL_X, +	OPT_TL_Y, +	OPT_BR_X, +	OPT_BR_Y, +	OPT_EQU_GROUP, +	OPT_SOURCE, +	OPT_EJECT, +	OPT_LOAD, +	OPT_ADF_MODE, +	OPT_ADF_SKEW, +	NUM_OPTIONS +}; + +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)*/ +} epsonds_conn_type; + +/* hardware description */ + +struct epsonds_device +{ +	struct epsonds_device *next; + +	epsonds_conn_type connection; + +	char *name; +	char *model; + +	unsigned int model_id; + +	SANE_Device sane; +	SANE_Range *x_range; +	SANE_Range *y_range; +	SANE_Range dpi_range; +	SANE_Byte alignment; + + +	SANE_Int *res_list;		/* list of resolutions */ +	SANE_Int *depth_list; +	SANE_Int max_depth;		/* max. color depth */ + +	SANE_Bool has_raw;		/* supports RAW format */ + +	SANE_Bool has_fb;		/* flatbed */ +	SANE_Range fbf_x_range;	        /* x range */ +	SANE_Range fbf_y_range;	        /* y range */ +	SANE_Byte fbf_alignment;	/* left, center, right */ +	SANE_Bool fbf_has_skew;		/* supports skew correction */ + +	SANE_Bool has_adf;		/* adf */ +	SANE_Range adf_x_range;	        /* x range */ +	SANE_Range adf_y_range;	        /* y range */ +	SANE_Bool adf_is_duplex;	/* supports duplex mode */ +	SANE_Bool adf_singlepass;	/* supports single pass duplex */ +	SANE_Bool adf_has_skew;		/* supports skew correction */ +	SANE_Bool adf_has_load;		/* supports load command */ +	SANE_Bool adf_has_eject;	/* supports eject command */ +	SANE_Byte adf_alignment;	/* left, center, right */ + +	SANE_Bool has_tpu;		/* tpu */ +	SANE_Range tpu_x_range;	        /* transparency unit x range */ +	SANE_Range tpu_y_range;	        /* transparency unit y range */ +}; + +typedef struct epsonds_device epsonds_device; + +typedef struct ring_buffer +{ +	SANE_Byte *ring, *wp, *rp, *end; +	SANE_Int fill, size; + +} ring_buffer; + +/* an instance of a scanner */ + +struct epsonds_scanner +{ +	struct epsonds_scanner *next; +	struct epsonds_device *hw; + +	int fd; + +	SANE_Option_Descriptor opt[NUM_OPTIONS]; +	Option_Value val[NUM_OPTIONS]; +	SANE_Parameters params; + +	SANE_Byte *buf, *line_buffer; +	ring_buffer *current, front, back; + +	SANE_Bool eof, scanning, canceling, locked, backside, mode_jpeg; + +	SANE_Int left, top, pages, dummy; + +	/* jpeg stuff */ + +	djpeg_dest_ptr jdst; +	struct jpeg_decompress_struct jpeg_cinfo; +	struct jpeg_error_mgr jpeg_err; +	SANE_Bool jpeg_header_seen; +}; + +typedef struct epsonds_scanner epsonds_scanner; + +struct mode_param +{ +	int color; +	int flags; +	int dropout_mask; +	int depth; +}; + +enum { +	MODE_BINARY, MODE_GRAY, MODE_COLOR +}; + +#endif diff --git a/backend/genesys.c b/backend/genesys.c index 913a048..548d0da 100644 --- a/backend/genesys.c +++ b/backend/genesys.c @@ -58,7 +58,7 @@   * SANE backend for Genesys Logic GL646/GL841/GL842/GL843/GL846/GL847/GL124 based scanners   */ -#define BUILD 2504 +#define BUILD 2506  #define BACKEND_NAME genesys  #include "genesys.h" @@ -157,6 +157,15 @@ static const SANE_Range enhance_range = {    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)  { @@ -3044,11 +3053,15 @@ genesys_send_shading_coefficient (Genesys_Device * dev)      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_CANONLIDE210 +        && dev->model->ccd_type!=CIS_CANONLIDE120 +        && dev->model->ccd_type!=CIS_CANONLIDE220)            target_code=0xdc00;          else            target_code=0xf000; @@ -5307,6 +5320,9 @@ calc_parameters (Genesys_Scanner * s)        s->dev->settings.brightness=0;      } +  /* cache expiration time */ +   s->dev->settings.expiration_time=s->val[OPT_EXPIRATION_TIME].w; +    return status;  } @@ -5895,6 +5911,17 @@ init_options (Genesys_Scanner * s)      }  #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 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"); @@ -6915,8 +6942,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, "Calibration filename set to:\n"); -  DBG (DBG_info, ">%s<\n", s->dev->calib_file); +  DBG (DBG_info, "%s: Calibration filename set to:\n", __FUNCTION__); +  DBG (DBG_info, "%s: >%s<\n", __FUNCTION__, s->dev->calib_file);    free(tmpstr);    /* now open file, fetch calibration records */ @@ -7193,37 +7220,35 @@ static SANE_Status set_calibration_value (Genesys_Scanner * s, int option, void  {    SANE_Status status=SANE_STATUS_GOOD;    char *tmp; -  Genesys_Calibration_Cache *cache;    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 */ +  /* 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;      } -  /* we can set no file name value */ +  /* 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", __FUNCTION__); +  DBG (DBG_info, "%s: >%s<\n", __FUNCTION__, s->dev->calib_file); -  /* clear device calibration cache */ -  while(dev->calibration_cache!=NULL) -    { -      cache=dev->calibration_cache; -      dev->calibration_cache=dev->calibration_cache->next; -      free(cache); -    } - +  DBGCOMPLETED;    return SANE_STATUS_GOOD;  } @@ -7418,6 +7443,7 @@ set_option_value (Genesys_Scanner * s, int option, void *val,        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; diff --git a/backend/genesys.conf.in b/backend/genesys.conf.in index 5300787..7899455 100644 --- a/backend/genesys.conf.in +++ b/backend/genesys.conf.in @@ -60,6 +60,12 @@ usb 0x04a9 0x1907  # Canon LiDE 210  usb 0x04a9 0x190a +# Canon LiDE 120 +usb 0x04a9 0x190e + +# Canon LiDE 220 +usb 0x04a9 0x190f +  # Canon 5600f  usb 0x04a9 0x1906 diff --git a/backend/genesys.h b/backend/genesys.h index fea3f3b..eab92bb 100644 --- a/backend/genesys.h +++ b/backend/genesys.h @@ -120,6 +120,7 @@ enum Genesys_Option    OPT_DISABLE_INTERPOLATION,    OPT_COLOR_FILTER,    OPT_CALIBRATION_FILE, +  OPT_EXPIRATION_TIME,    OPT_SENSOR_GROUP,    OPT_SCAN_SW, diff --git a/backend/genesys_devices.c b/backend/genesys_devices.c index 213b9c9..4358e94 100644 --- a/backend/genesys_devices.c +++ b/backend/genesys_devices.c @@ -660,6 +660,30 @@ static Genesys_Sensor Sensor[] = {     {2.1, 2.1, 2.1},     {NULL, NULL, NULL}}    , + +  /* CANONLIDE120 */ +  {CIS_CANONLIDE120, +   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 210 sensor */    {CIS_CANONLIDE210,     2400,	/* optical resolution */ @@ -683,6 +707,29 @@ static Genesys_Sensor Sensor[] = {     {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) */ @@ -1854,6 +1901,59 @@ static Genesys_Model canon_lide_110_model = {    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 (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_CANONLIDE120, +  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_210_model = {    "canon-lide-210",		/* Name */ @@ -1908,6 +2008,59 @@ static Genesys_Model canon_lide_210_model = {    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 */ @@ -3507,7 +3660,9 @@ static Genesys_USB_Device_Entry genesys_usb_device_list[] = {    {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}  }; diff --git a/backend/genesys_gl124.c b/backend/genesys_gl124.c index 86aa4ee..eaac873 100644 --- a/backend/genesys_gl124.c +++ b/backend/genesys_gl124.c @@ -852,7 +852,7 @@ gl124_init_motor_regs_scan (Genesys_Device * dev,      }    else      { -      min_speed = 600; +      min_speed = 900;        if(dev->model->ccd_type==MOTOR_CANONLIDE110)          {            min_speed = 300; @@ -2108,6 +2108,17 @@ gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home)        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", __FUNCTION__, 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); @@ -2202,12 +2213,13 @@ gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home)  /** @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) +gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse)  {    Genesys_Register_Set local_reg[GENESYS_GL124_MAX_REGS];    SANE_Status status; @@ -2242,9 +2254,7 @@ gl124_feed (Genesys_Device * dev, unsigned int steps)                                   SCAN_FLAG_IGNORE_LINE_DISTANCE);    if (status != SANE_STATUS_GOOD)      { -      DBG (DBG_error, -           "gl124_feed: failed to set up registers: %s\n", -           sane_strstatus (status)); +      DBG (DBG_error, "%s: failed to set up registers: %s\n", __FUNCTION__, sane_strstatus (status));        DBGCOMPLETED;        return status;      } @@ -2262,6 +2272,13 @@ gl124_feed (Genesys_Device * dev, unsigned int steps)    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)); @@ -2653,7 +2670,7 @@ gl124_init_regs_for_scan (Genesys_Device * dev)    if(channels*dev->settings.yres>=600 && move>700)      { -      status = gl124_feed (dev, move-500); +      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__); @@ -3511,12 +3528,13 @@ gl124_init_gpio (Genesys_Device * dev)    DBGSTART;    /* per model GPIO layout */ -  if (strcmp (dev->model->name, "canon-lide-110") == 0) +  if ((strcmp (dev->model->name, "canon-lide-110") == 0) +    ||(strcmp (dev->model->name, "canon-lide-120") == 0))      {        idx = 0;      }    else -    {				/* canon LiDE 210 case */ +    {				/* canon LiDE 210 and 220 case */        idx = 1;      } @@ -3544,12 +3562,13 @@ gl124_init_memory_layout (Genesys_Device * dev)    DBGSTART;    /* point to per model memory layout */ -  if (strcmp (dev->model->name, "canon-lide-110") == 0) +  if ((strcmp (dev->model->name, "canon-lide-110") == 0) +    ||(strcmp (dev->model->name, "canon-lide-120") == 0))      {        idx = 0;      }    else -    {				/* canon LiDE 210 case */ +    {				/* canon LiDE 210 and 220 case */        idx = 1;      } diff --git a/backend/genesys_gl124.h b/backend/genesys_gl124.h index 8b9998a..ae8016c 100644 --- a/backend/genesys_gl124.h +++ b/backend/genesys_gl124.h @@ -620,11 +620,23 @@ static Sensor_Profile sensors[]={  	{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}, +        /* LiDE 120 */ +	{CIS_CANONLIDE120,  600, 1,  2768, 0x0f, 0x9f, 0x55, 2584, 154,  101,  388,  574,  393, NULL      , 0x00, 0x0c, 0x20, 0x21}, +	{CIS_CANONLIDE120,  600, 0,  5360, 0x0f, 0x9f, 0x55, 5168, 163,  101,  388,  574,  393, NULL      , 0x00, 0x0a, 0x20, 0x21}, +	{CIS_CANONLIDE120, 1200, 0, 10528, 0x0f, 0x9f, 0x55, 5168, 163,  101,  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 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}, + +        /* 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},  }; @@ -704,7 +716,7 @@ SANE_Status gl124_send_shading_data (Genesys_Device * dev, uint8_t * data, int s  #ifndef UNIT_TESTING  static  #endif -SANE_Status gl124_feed (Genesys_Device * dev, unsigned int steps); +SANE_Status gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse);  GENESYS_STATIC SANE_Status  gl124_stop_action (Genesys_Device * dev); diff --git a/backend/genesys_low.c b/backend/genesys_low.c index 63420e4..0af2149 100644 --- a/backend/genesys_low.c +++ b/backend/genesys_low.c @@ -1437,6 +1437,7 @@ sanei_genesys_wait_for_home (Genesys_Device * dev)    SANE_Status status;    uint8_t val;    int loop; +  int max=300;    DBGSTART; @@ -1492,7 +1493,14 @@ sanei_genesys_wait_for_home (Genesys_Device * dev)              }        ++loop;      } -  while (loop < 300 && !(val & HOMESNR) && status == SANE_STATUS_GOOD); +  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", __FUNCTION__, max/10); +      return SANE_STATUS_IO_ERROR; +    }    DBGCOMPLETED;    return status; @@ -1755,7 +1763,11 @@ int sanei_genesys_get_lowest_dpi(Genesys_Device *dev)  /** @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, @@ -1771,22 +1783,20 @@ sanei_genesys_is_compatible_calibration (Genesys_Device * dev,    if(dev->model->cmd_set->calculate_current_setup==NULL)      { -      DBG (DBG_proc, -	   "sanei_genesys_is_compatible_calibration: no calculate_setup, non compatible cache\n"); +      DBG (DBG_proc, "%s: no calculate_setup, non compatible cache\n", __FUNCTION__);        return SANE_STATUS_UNSUPPORTED;      }    status = dev->model->cmd_set->calculate_current_setup (dev);    if (status != SANE_STATUS_GOOD)      { -      DBG (DBG_error, -	   "sanei_genesys_is_compatible_calibration: failed to calculate current setup: %s\n", +      DBG (DBG_error, "%s: failed to calculate current setup: %s\n", __FUNCTION__,  	   sane_strstatus (status));        return status;      }    dev->current_setup.scan_method = dev->settings.scan_method; -  DBG (DBG_proc, "sanei_genesys_is_compatible_calibration: checking\n"); +  DBG (DBG_proc, "%s: checking\n", __FUNCTION__);    /* 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 */ @@ -1804,39 +1814,36 @@ 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);    if (dev->current_setup.half_ccd != cache->used_setup.half_ccd)      { -      DBG (DBG_io, -	   "sanei_genesys_is_compatible_calibration: half_ccd=%d, used=%d\n", +      DBG (DBG_io, "%s: half_ccd=%d, used=%d\n", __FUNCTION__,  	   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, -	   "sanei_genesys_is_compatible_calibration: current method=%d, used=%d\n", +      DBG (DBG_io, "%s: current method=%d, used=%d\n", __FUNCTION__,  	   dev->current_setup.scan_method, cache->used_setup.scan_method);        compatible = 0;      }    if (!compatible)      { -      DBG (DBG_proc, -	   "sanei_genesys_is_compatible_calibration: completed, non compatible cache\n"); +      DBG (DBG_proc, "%s: completed, non compatible cache\n", __FUNCTION__);        return SANE_STATUS_UNSUPPORTED;      } -  /* a cache entry expires after 60 minutes for non sheetfed scanners */ +  /* 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) +  if(for_overwrite == SANE_FALSE && dev->settings.expiration_time >=0)      {        gettimeofday (&time, NULL); -      if ((time.tv_sec - cache->last_calibration > 60 * 60) +      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, -               "sanei_genesys_is_compatible_calibration: expired entry, non compatible cache\n"); +          DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __FUNCTION__);            return SANE_STATUS_UNSUPPORTED;          }      } diff --git a/backend/genesys_low.h b/backend/genesys_low.h index b1f29e1..b5a0a8f 100644 --- a/backend/genesys_low.h +++ b/backend/genesys_low.h @@ -382,6 +382,8 @@ Genesys_Color_Order;  #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 @@ -705,6 +707,9 @@ typedef struct    /**< value for brightness enhancement in the [-100..100] range */    int brightness; +   +  /**< cahe entries expiration time */ +  int expiration_time;  } Genesys_Settings;  typedef struct Genesys_Current_Setup diff --git a/backend/hp5590.c b/backend/hp5590.c index 8db3d5e..7b1cd60 100644 --- a/backend/hp5590.c +++ b/backend/hp5590.c @@ -1239,6 +1239,14 @@ convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)  	      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; +        } +        memcpy (ptr, buf, bytes_per_line);      }    free (buf); diff --git a/backend/pixma.c b/backend/pixma.c index 4c7ec46..3396155 100644 --- a/backend/pixma.c +++ b/backend/pixma.c @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> diff --git a/backend/pixma.h b/backend/pixma.h index af38725..eedf74d 100644 --- a/backend/pixma.h +++ b/backend/pixma.h @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> @@ -114,7 +114,7 @@ typedef uint32_t uint32_t;  /**@{*/  #define PIXMA_VERSION_MAJOR 0  #define PIXMA_VERSION_MINOR 17 -#define PIXMA_VERSION_BUILD 14 +#define PIXMA_VERSION_BUILD 17  /**@}*/  /** \name Error codes */ diff --git a/backend/pixma_common.c b/backend/pixma_common.c index 771a5af..0945a69 100644 --- a/backend/pixma_common.c +++ b/backend/pixma_common.c @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> diff --git a/backend/pixma_common.h b/backend/pixma_common.h index 55ab570..069f8b8 100644 --- a/backend/pixma_common.h +++ b/backend/pixma_common.h @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>     This file is part of the SANE package. diff --git a/backend/pixma_imageclass.c b/backend/pixma_imageclass.c index b2526fa..3995805 100644 --- a/backend/pixma_imageclass.c +++ b/backend/pixma_imageclass.c @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org>     Copyright (C) 2008 Dennis Lou, dlou 99 at yahoo dot com @@ -95,8 +95,13 @@  #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  enum iclass_state_t @@ -799,6 +804,11 @@ const pixma_config_t pixma_iclass_devices[] = {    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 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 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 (NULL, NULL, 0, 0, 0, 0, 0, 0)  }; diff --git a/backend/pixma_io_sanei.c b/backend/pixma_io_sanei.c index 59d1602..08ec525 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-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>     This file is part of the SANE package. diff --git a/backend/pixma_mp150.c b/backend/pixma_mp150.c index 22ca41d..79711fe 100644 --- a/backend/pixma_mp150.c +++ b/backend/pixma_mp150.c @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> @@ -224,6 +224,10 @@  #define MG2900_PID 0x1780  #define E460_PID 0x1788 +/* 2015 new devices (untested) */ +#define MX490_PID 0x1787 +#define E480_PID 0x1789 +  /* Generation 4 XML messages that encapsulates the Pixma protocol messages */  #define XML_START_1   \ @@ -1149,6 +1153,7 @@ post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib)                && s->cfg->pid != MG5300_PID                && s->cfg->pid != MG5500_PID                && s->cfg->pid != MG6300_PID +              && s->cfg->pid != MG6400_PID                && s->cfg->pid != MG7100_PID)                reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); @@ -1817,5 +1822,9 @@ 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 */ +  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), +    END_OF_DEVICE_LIST  }; diff --git a/backend/pixma_mp730.c b/backend/pixma_mp730.c index 58d1994..2184ff7 100644 --- a/backend/pixma_mp730.c +++ b/backend/pixma_mp730.c @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> diff --git a/backend/pixma_mp750.c b/backend/pixma_mp750.c index e46a942..8d2d94c 100644 --- a/backend/pixma_mp750.c +++ b/backend/pixma_mp750.c @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. -   Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> +   Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>     Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>     This file is part of the SANE package. diff --git a/backend/pixma_mp810.c b/backend/pixma_mp810.c index 59e96eb..e8bf75f 100644 --- a/backend/pixma_mp810.c +++ b/backend/pixma_mp810.c @@ -1,6 +1,6 @@  /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2014 Rolf Bensch <rolf at bensch hyphen online dot de> + Copyright (C) 2011-2015 Rolf Bensch <rolf at bensch hyphen online dot de>   Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org>   Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de> @@ -657,6 +657,23 @@ static unsigned calc_shifting (pixma_t * s)        }        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;    } @@ -850,7 +867,7 @@ static int send_scan_param (pixma_t * s)       * 0x24 |   1   |   all   | 0x01       * -----+-------+---------+---------------------------       * 0x25 |   1   | default | 0x00; cs8800f: 0x01 -     *      |       |   tpu   | 0x00; cs9000f, mg8200: 0x01 +     *      |       |   tpu   | 0x00; cs9000f, mg8200, mp990: 0x01       *      |       |  tpuir  | cs9000f: 0x00       * -----+-------+---------+---------------------------       *  ... |   1   |   all   | 0x00 @@ -908,8 +925,8 @@ static int send_scan_param (pixma_t * s)      data[0x23] = 0x02;      data[0x24] = 0x01; -    /* MG8200 addition */ -    if (s->cfg->pid == MG8200_PID) +    /* MG8200 & MP990 addition */ +    if (s->cfg->pid == MG8200_PID || s->cfg->pid == MP990_PID)      {        if (is_scanning_from_tpu (s))        { | 
