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)) { |