summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
commit6e9c41a892ed0e0da326e0278b3221ce3f5713b8 (patch)
tree2e301d871bbeeb44aa57ff9cc070fcf3be484487 /tools
Initial import of sane-backends version 1.0.24-1.2
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am79
-rw-r--r--tools/Makefile.in916
-rw-r--r--tools/README74
-rw-r--r--tools/RenSaneDlls.cmd33
-rwxr-xr-xtools/check-po.awk173
-rw-r--r--tools/check-usb-chip.c4128
-rw-r--r--tools/gamma4scanimage.c140
-rw-r--r--tools/hotplug-ng/README46
-rwxr-xr-xtools/hotplug-ng/libsane.hotplug29
-rw-r--r--tools/hotplug/README35
-rwxr-xr-xtools/hotplug/libusbscanner35
-rwxr-xr-xtools/libtool-get-dll-ext19
-rw-r--r--tools/mustek600iin-off.c199
-rwxr-xr-xtools/openbsd/attach20
-rwxr-xr-xtools/openbsd/detach22
-rw-r--r--tools/sane-backends.pc.in14
-rw-r--r--tools/sane-config.in91
-rw-r--r--tools/sane-desc.c4056
-rw-r--r--tools/sane-find-scanner.c2100
-rw-r--r--tools/umax_pp.c573
-rwxr-xr-xtools/xerox60
21 files changed, 12842 insertions, 0 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..7c2a616
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,79 @@
+## Makefile.am -- an automake template for Makefile.in file
+## Copyright (C) 2009 Chris Bagwell and Sane Developers.
+##
+## This file is part of the "Sane" build infra-structure. See
+## included LICENSE file for license information.
+
+AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_builddir)/include \
+ -I$(top_srcdir)/include
+
+bin_PROGRAMS = sane-find-scanner gamma4scanimage
+noinst_PROGRAMS = sane-desc umax_pp
+
+if CROSS_COMPILING
+HOTPLUG =
+HOTPLUG_DIRS =
+HOTPLUG_DIR =
+else
+HOTPLUG = hal/libsane.fdi hotplug/libsane.usermap hotplug-ng/libsane.db \
+ udev/libsane.rules
+HOTPLUG_DIRS = hal hotplug hotplug-ng udev
+HOTPLUG_DIR = dirs
+endif
+
+bin_SCRIPTS = sane-config
+noinst_SCRIPTS = $(HOTPLUG)
+BUILT_SOURCES = $(HOTPLUG_DIR)
+CLEANFILES = $(bin_SCRIPTS) $(dist_noinst_SCRIPTS)
+
+EXTRA_DIST = check-po.awk libtool-get-dll-ext mustek600iin-off.c \
+ RenSaneDlls.cmd README xerox
+
+sane_find_scanner_SOURCES = sane-find-scanner.c check-usb-chip.c \
+ ../backend/sane_strstatus.c
+sane_find_scanner_LDADD = ../sanei/libsanei.la ../lib/liblib.la \
+ @USB_LIBS@ @IEEE1284_LIBS@ @SCSI_LIBS@
+
+gamma4scanimage_SOURCES = gamma4scanimage.c
+gamma4scanimage_LDADD = @MATH_LIB@
+
+umax_pp_SOURCES = umax_pp.c ../backend/umax_pp_low.c
+umax_pp_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax_pp_low
+umax_pp_LDADD = ../sanei/libsanei.la ../lib/liblib.la @MATH_LIB@
+
+sane_desc_SOURCES = sane-desc.c
+sane_desc_LDADD = ../sanei/libsanei.la ../lib/liblib.la
+
+EXTRA_DIST += hotplug/README hotplug/libusbscanner
+EXTRA_DIST += hotplug-ng/README hotplug-ng/libsane.hotplug
+EXTRA_DIST += openbsd/attach openbsd/detach
+
+pkgconfigdir = @libdir@/pkgconfig
+pkgconfig_DATA = sane-backends.pc
+
+# When build directory is not same as source directory then any
+# subdirectories that targets use must be manually created (under
+# the build directory that is).
+dirs:
+ for subdir in $(HOTPLUG_DIRS); do \
+ $(MKDIR_P) $$subdir || exit 1; \
+ done
+
+hotplug/libsane.usermap: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m usermap -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 1 > $@
+
+hotplug-ng/libsane.db: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m db -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 0 > $@
+
+udev/libsane.rules: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m udev -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 0 > $@
+
+hal/libsane.fdi: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m hal -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 0 > $@
+
+clean-local:
+ rm -f $(HOTPLUG)
diff --git a/tools/Makefile.in b/tools/Makefile.in
new file mode 100644
index 0000000..367a70b
--- /dev/null
+++ b/tools/Makefile.in
@@ -0,0 +1,916 @@
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = sane-find-scanner$(EXEEXT) gamma4scanimage$(EXEEXT)
+noinst_PROGRAMS = sane-desc$(EXEEXT) umax_pp$(EXEEXT)
+subdir = tools
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/mkinstalldirs $(srcdir)/sane-config.in \
+ $(srcdir)/sane-backends.pc.in $(top_srcdir)/depcomp README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/byteorder.m4 \
+ $(top_srcdir)/m4/stdint.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/include/sane/config.h
+CONFIG_CLEAN_FILES = sane-config sane-backends.pc
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(pkgconfigdir)"
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
+am_gamma4scanimage_OBJECTS = gamma4scanimage.$(OBJEXT)
+gamma4scanimage_OBJECTS = $(am_gamma4scanimage_OBJECTS)
+gamma4scanimage_DEPENDENCIES =
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_sane_desc_OBJECTS = sane-desc.$(OBJEXT)
+sane_desc_OBJECTS = $(am_sane_desc_OBJECTS)
+sane_desc_DEPENDENCIES = ../sanei/libsanei.la ../lib/liblib.la
+am_sane_find_scanner_OBJECTS = sane-find-scanner.$(OBJEXT) \
+ check-usb-chip.$(OBJEXT) sane_strstatus.$(OBJEXT)
+sane_find_scanner_OBJECTS = $(am_sane_find_scanner_OBJECTS)
+sane_find_scanner_DEPENDENCIES = ../sanei/libsanei.la ../lib/liblib.la
+am_umax_pp_OBJECTS = umax_pp-umax_pp.$(OBJEXT) \
+ umax_pp-umax_pp_low.$(OBJEXT)
+umax_pp_OBJECTS = $(am_umax_pp_OBJECTS)
+umax_pp_DEPENDENCIES = ../sanei/libsanei.la ../lib/liblib.la
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+SCRIPTS = $(bin_SCRIPTS) $(noinst_SCRIPTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/sane
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(gamma4scanimage_SOURCES) $(sane_desc_SOURCES) \
+ $(sane_find_scanner_SOURCES) $(umax_pp_SOURCES)
+DIST_SOURCES = $(gamma4scanimage_SOURCES) $(sane_desc_SOURCES) \
+ $(sane_find_scanner_SOURCES) $(umax_pp_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(pkgconfig_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AVAHI_CFLAGS = @AVAHI_CFLAGS@
+AVAHI_LIBS = @AVAHI_LIBS@
+AWK = @AWK@
+BACKENDS = @BACKENDS@
+BACKEND_CONFS_ENABLED = @BACKEND_CONFS_ENABLED@
+BACKEND_LIBS_ENABLED = @BACKEND_LIBS_ENABLED@
+BACKEND_MANS_ENABLED = @BACKEND_MANS_ENABLED@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCLEAN_FILES = @DISTCLEAN_FILES@
+DLLTOOL = @DLLTOOL@
+DL_LIBS = @DL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DVIPS = @DVIPS@
+DYNAMIC_FLAG = @DYNAMIC_FLAG@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GPHOTO2_CPPFLAGS = @GPHOTO2_CPPFLAGS@
+GPHOTO2_LDFLAGS = @GPHOTO2_LDFLAGS@
+GPHOTO2_LIBS = @GPHOTO2_LIBS@
+GREP = @GREP@
+HAVE_GPHOTO2 = @HAVE_GPHOTO2@
+IEEE1284_LIBS = @IEEE1284_LIBS@
+INCLUDES = @INCLUDES@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_LOCKPATH = @INSTALL_LOCKPATH@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JPEG_LIBS = @JPEG_LIBS@
+LATEX = @LATEX@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUSB_1_0_CFLAGS = @LIBUSB_1_0_CFLAGS@
+LIBUSB_1_0_LIBS = @LIBUSB_1_0_LIBS@
+LIBV4L_CFLAGS = @LIBV4L_CFLAGS@
+LIBV4L_LIBS = @LIBV4L_LIBS@
+LINKER_RPATH = @LINKER_RPATH@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCKPATH_GROUP = @LOCKPATH_GROUP@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINDEX = @MAKEINDEX@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATH_LIB = @MATH_LIB@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NUMBER_VERSION = @NUMBER_VERSION@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PRELOADABLE_BACKENDS = @PRELOADABLE_BACKENDS@
+PRELOADABLE_BACKENDS_ENABLED = @PRELOADABLE_BACKENDS_ENABLED@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+RESMGR_LIBS = @RESMGR_LIBS@
+SANEI_SANEI_JPEG_LO = @SANEI_SANEI_JPEG_LO@
+SANE_CONFIG_PATH = @SANE_CONFIG_PATH@
+SCSI_LIBS = @SCSI_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNMP_CONFIG_PATH = @SNMP_CONFIG_PATH@
+SOCKET_LIBS = @SOCKET_LIBS@
+STRICT_LDFLAGS = @STRICT_LDFLAGS@
+STRIP = @STRIP@
+SYSLOG_LIBS = @SYSLOG_LIBS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+TIFF_LIBS = @TIFF_LIBS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+V_MAJOR = @V_MAJOR@
+V_MINOR = @V_MINOR@
+V_REV = @V_REV@
+XGETTEXT = @XGETTEXT@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+effective_target = @effective_target@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+locksanedir = @locksanedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_builddir)/include \
+ -I$(top_srcdir)/include
+
+@CROSS_COMPILING_FALSE@HOTPLUG = hal/libsane.fdi hotplug/libsane.usermap hotplug-ng/libsane.db \
+@CROSS_COMPILING_FALSE@ udev/libsane.rules
+
+@CROSS_COMPILING_TRUE@HOTPLUG =
+@CROSS_COMPILING_FALSE@HOTPLUG_DIRS = hal hotplug hotplug-ng udev
+@CROSS_COMPILING_TRUE@HOTPLUG_DIRS =
+@CROSS_COMPILING_FALSE@HOTPLUG_DIR = dirs
+@CROSS_COMPILING_TRUE@HOTPLUG_DIR =
+bin_SCRIPTS = sane-config
+noinst_SCRIPTS = $(HOTPLUG)
+BUILT_SOURCES = $(HOTPLUG_DIR)
+CLEANFILES = $(bin_SCRIPTS) $(dist_noinst_SCRIPTS)
+EXTRA_DIST = check-po.awk libtool-get-dll-ext mustek600iin-off.c \
+ RenSaneDlls.cmd README xerox hotplug/README \
+ hotplug/libusbscanner hotplug-ng/README \
+ hotplug-ng/libsane.hotplug openbsd/attach openbsd/detach
+sane_find_scanner_SOURCES = sane-find-scanner.c check-usb-chip.c \
+ ../backend/sane_strstatus.c
+
+sane_find_scanner_LDADD = ../sanei/libsanei.la ../lib/liblib.la \
+ @USB_LIBS@ @IEEE1284_LIBS@ @SCSI_LIBS@
+
+gamma4scanimage_SOURCES = gamma4scanimage.c
+gamma4scanimage_LDADD = @MATH_LIB@
+umax_pp_SOURCES = umax_pp.c ../backend/umax_pp_low.c
+umax_pp_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax_pp_low
+umax_pp_LDADD = ../sanei/libsanei.la ../lib/liblib.la @MATH_LIB@
+sane_desc_SOURCES = sane-desc.c
+sane_desc_LDADD = ../sanei/libsanei.la ../lib/liblib.la
+pkgconfigdir = @libdir@/pkgconfig
+pkgconfig_DATA = sane-backends.pc
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tools/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu tools/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+sane-config: $(top_builddir)/config.status $(srcdir)/sane-config.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+sane-backends.pc: $(top_builddir)/config.status $(srcdir)/sane-backends.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+gamma4scanimage$(EXEEXT): $(gamma4scanimage_OBJECTS) $(gamma4scanimage_DEPENDENCIES) $(EXTRA_gamma4scanimage_DEPENDENCIES)
+ @rm -f gamma4scanimage$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gamma4scanimage_OBJECTS) $(gamma4scanimage_LDADD) $(LIBS)
+
+sane-desc$(EXEEXT): $(sane_desc_OBJECTS) $(sane_desc_DEPENDENCIES) $(EXTRA_sane_desc_DEPENDENCIES)
+ @rm -f sane-desc$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sane_desc_OBJECTS) $(sane_desc_LDADD) $(LIBS)
+
+sane-find-scanner$(EXEEXT): $(sane_find_scanner_OBJECTS) $(sane_find_scanner_DEPENDENCIES) $(EXTRA_sane_find_scanner_DEPENDENCIES)
+ @rm -f sane-find-scanner$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sane_find_scanner_OBJECTS) $(sane_find_scanner_LDADD) $(LIBS)
+
+umax_pp$(EXEEXT): $(umax_pp_OBJECTS) $(umax_pp_DEPENDENCIES) $(EXTRA_umax_pp_DEPENDENCIES)
+ @rm -f umax_pp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(umax_pp_OBJECTS) $(umax_pp_LDADD) $(LIBS)
+install-binSCRIPTS: $(bin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-usb-chip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gamma4scanimage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sane-desc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sane-find-scanner.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sane_strstatus.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/umax_pp-umax_pp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/umax_pp-umax_pp_low.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@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 $<
+
+.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) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+sane_strstatus.o: ../backend/sane_strstatus.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sane_strstatus.o -MD -MP -MF $(DEPDIR)/sane_strstatus.Tpo -c -o sane_strstatus.o `test -f '../backend/sane_strstatus.c' || echo '$(srcdir)/'`../backend/sane_strstatus.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sane_strstatus.Tpo $(DEPDIR)/sane_strstatus.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../backend/sane_strstatus.c' object='sane_strstatus.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sane_strstatus.o `test -f '../backend/sane_strstatus.c' || echo '$(srcdir)/'`../backend/sane_strstatus.c
+
+sane_strstatus.obj: ../backend/sane_strstatus.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sane_strstatus.obj -MD -MP -MF $(DEPDIR)/sane_strstatus.Tpo -c -o sane_strstatus.obj `if test -f '../backend/sane_strstatus.c'; then $(CYGPATH_W) '../backend/sane_strstatus.c'; else $(CYGPATH_W) '$(srcdir)/../backend/sane_strstatus.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sane_strstatus.Tpo $(DEPDIR)/sane_strstatus.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../backend/sane_strstatus.c' object='sane_strstatus.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sane_strstatus.obj `if test -f '../backend/sane_strstatus.c'; then $(CYGPATH_W) '../backend/sane_strstatus.c'; else $(CYGPATH_W) '$(srcdir)/../backend/sane_strstatus.c'; fi`
+
+umax_pp-umax_pp.o: umax_pp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT umax_pp-umax_pp.o -MD -MP -MF $(DEPDIR)/umax_pp-umax_pp.Tpo -c -o umax_pp-umax_pp.o `test -f 'umax_pp.c' || echo '$(srcdir)/'`umax_pp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/umax_pp-umax_pp.Tpo $(DEPDIR)/umax_pp-umax_pp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax_pp.c' object='umax_pp-umax_pp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o umax_pp-umax_pp.o `test -f 'umax_pp.c' || echo '$(srcdir)/'`umax_pp.c
+
+umax_pp-umax_pp.obj: umax_pp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT umax_pp-umax_pp.obj -MD -MP -MF $(DEPDIR)/umax_pp-umax_pp.Tpo -c -o umax_pp-umax_pp.obj `if test -f 'umax_pp.c'; then $(CYGPATH_W) 'umax_pp.c'; else $(CYGPATH_W) '$(srcdir)/umax_pp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/umax_pp-umax_pp.Tpo $(DEPDIR)/umax_pp-umax_pp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax_pp.c' object='umax_pp-umax_pp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o umax_pp-umax_pp.obj `if test -f 'umax_pp.c'; then $(CYGPATH_W) 'umax_pp.c'; else $(CYGPATH_W) '$(srcdir)/umax_pp.c'; fi`
+
+umax_pp-umax_pp_low.o: ../backend/umax_pp_low.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT umax_pp-umax_pp_low.o -MD -MP -MF $(DEPDIR)/umax_pp-umax_pp_low.Tpo -c -o umax_pp-umax_pp_low.o `test -f '../backend/umax_pp_low.c' || echo '$(srcdir)/'`../backend/umax_pp_low.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/umax_pp-umax_pp_low.Tpo $(DEPDIR)/umax_pp-umax_pp_low.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../backend/umax_pp_low.c' object='umax_pp-umax_pp_low.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o umax_pp-umax_pp_low.o `test -f '../backend/umax_pp_low.c' || echo '$(srcdir)/'`../backend/umax_pp_low.c
+
+umax_pp-umax_pp_low.obj: ../backend/umax_pp_low.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT umax_pp-umax_pp_low.obj -MD -MP -MF $(DEPDIR)/umax_pp-umax_pp_low.Tpo -c -o umax_pp-umax_pp_low.obj `if test -f '../backend/umax_pp_low.c'; then $(CYGPATH_W) '../backend/umax_pp_low.c'; else $(CYGPATH_W) '$(srcdir)/../backend/umax_pp_low.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/umax_pp-umax_pp_low.Tpo $(DEPDIR)/umax_pp-umax_pp_low.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../backend/umax_pp_low.c' object='umax_pp-umax_pp_low.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(umax_pp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o umax_pp-umax_pp_low.obj `if test -f '../backend/umax_pp_low.c'; then $(CYGPATH_W) '../backend/umax_pp_low.c'; else $(CYGPATH_W) '$(srcdir)/../backend/umax_pp_low.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-binSCRIPTS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
+ uninstall-pkgconfigDATA
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libtool clean-local \
+ clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-binSCRIPTS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-binSCRIPTS \
+ uninstall-pkgconfigDATA
+
+
+# When build directory is not same as source directory then any
+# subdirectories that targets use must be manually created (under
+# the build directory that is).
+dirs:
+ for subdir in $(HOTPLUG_DIRS); do \
+ $(MKDIR_P) $$subdir || exit 1; \
+ done
+
+hotplug/libsane.usermap: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m usermap -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 1 > $@
+
+hotplug-ng/libsane.db: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m db -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 0 > $@
+
+udev/libsane.rules: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m udev -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 0 > $@
+
+hal/libsane.fdi: $(wildcard ${top_srcdir}/doc/descriptions/*.desc) $(wildcard ${top_srcdir}/doc/descriptions-external/*.desc) sane-desc
+ @./sane-desc -m hal -s ${top_srcdir}/doc/descriptions:${top_srcdir}/doc/descriptions-external \
+ -d 0 > $@
+
+clean-local:
+ rm -f $(HOTPLUG)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tools/README b/tools/README
new file mode 100644
index 0000000..6002113
--- /dev/null
+++ b/tools/README
@@ -0,0 +1,74 @@
+2006-05-10
+
+This directory contains various tools that may be useful:
+
+ hotplug/:
+ Linux hotplug script and an automatically generated config file
+ (libsane.usermap) used to change the permissions on the libusb "device
+ nodes" in /proc/bus/usb/ when a scanner is plugged in. For newer Linux
+ kernels, you may need to use udev instead. Please read the README file
+ in this directory for instructions.
+
+ hotplug-ng/:
+ Linux hotplug-ng script and an automatically generated config file
+ (libsane.db) used to change the permissions on the libusb "device nodes"
+ in /proc/bus/usb/ when a scanner is plugged in. For newer Linux kernels,
+ you may need to use udev instead. Please read the README file in this
+ directory for instructions.
+
+ udev/:
+ Contains a automatically generated udev rules file. udev now replaces
+ hotplug and provides all the functionalities of hotplug. libusb 0.1.12
+ or newer is necessary.
+
+ openbsd/:
+ Contains example scripts for hotplugd(8) for USB scanners accessed via
+ libusb.
+
+ sane-find-scanner:
+ Attempts to find a SCSI scanner attached to your system.
+ Invoke with "sane-find-scanner -h" to get command-line
+ syntax. More details can be found in the man page
+ sane-find-scanner(1).
+
+ xerox:
+ A simple script to make photocopies ("xeroxing"). In
+ the script, you may need to adjust the device name
+ assigned to variable DEV and the resolution assigned
+ to variable RES as well as the paper with and height
+ (variables WIDTH and HEIGHT, respectively.
+
+ mustek600iin-off:
+ Allows you to turn off a Mustek 600 II N scanner.
+ Use "make mustek600iin-off" to compile.
+
+ umax_pp:
+ Command line utility to scan on UMAX astra 1220P,
+ 1600P and 2000P, without using the backend. So that
+ scanner protocol can be tested directly.
+
+ gamma4scanimage: Creates a gamma table in the format expected by scanimage.
+ You can define a gamma value, shadow and highlight.
+ Take a look at manual page gamma4scanimage for further information.
+
+ RenSaneDlls.cmd: Convert backend-DLL-filenames according to 8.3 naming
+ convention necessary for DLLs on OS/2.
+
+Maybe useful for SANE developers:
+
+ sane-config:
+ Show SANE version, linker flags etc. Might be useful for
+ frontend developers.
+
+ sane-desc:
+ Generate SANE webpages (and ASCII lists) from backend .desc files.
+ Run "sane-desc --help" for details. The default lists are generated
+ in doc/Makefile.
+
+ check-po.awk:
+ Print untranslated and fuzzy messages and their line numbers in the
+ source code and po file. Example:
+ cd po/ ; ../tools/check-po.awk sane-backends.de.po
+ You may need to adjust the path of awk in the first line of the
+ script. More documentation is in the script itself.
+
diff --git a/tools/RenSaneDlls.cmd b/tools/RenSaneDlls.cmd
new file mode 100644
index 0000000..2973f85
--- /dev/null
+++ b/tools/RenSaneDlls.cmd
@@ -0,0 +1,33 @@
+/* REXX */
+/* Convert backend-DLL-filenames according to 8.3 naming convention */
+/* necessary for DLLs on OS/2 (C) Franz Bakan 2004,2005 */
+/* */
+/* This file is part of the SANE package. */
+/* */
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License as */
+/* published by the Free Software Foundation; either version 2 of the */
+/* License, or (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+CALL RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
+CALL SysLoadFuncs
+
+rc = SysFileTree('\usr\lib\sane\libsane-*.dll',dlls,O)
+DO i=1 TO dlls.0
+ PARSE VALUE dlls.i WITH front 'libsane-' backend '.dll'
+ IF length(backend) > 7 THEN
+ COPY dlls.i front||LEFT(backend,2)||RIGHT(backend,5,' ')||'.dll'
+ ELSE
+ IF length(backend) > 0 THEN COPY dlls.i front||backend||'.dll'
+ DEL dlls.i
+END /* do */
diff --git a/tools/check-po.awk b/tools/check-po.awk
new file mode 100755
index 0000000..25e0728
--- /dev/null
+++ b/tools/check-po.awk
@@ -0,0 +1,173 @@
+#!/bin/awk -f
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA.
+
+
+# This script will (hopefully!) check the completeness of a .po
+# translation file. It will report untranslated strings, as well
+# as fuzzy ones. It will print a summarry at the end of the check
+# that says how many strings there are, how many are translated
+# (and the percentage it represents), how many are fuzzy (and the
+# percentage it represents amongst translated strings), and how
+# many aree un-translated (and the percentage it represents).
+# It will _not_ tell you wether your file is syntactically correct
+# (eg. check for terminating double quotes!). And of course it
+# will _not_ tell you wether the translations are correct! ;-]
+#
+# It was originaly been written for SANE backends translations, but
+# shall be able to check any .po file.
+#
+# Originally writen by Yann E. MORIN
+# <yann dot morin dot 1998 at anciens dot enib dot fr>
+#
+# Output will look like :
+# [./src/foobar.c:2345](321)- "This is the string"
+# \____________/ \__/ \_/ | \________________/
+# | | | | |
+# | | | | \-> Original untranslated string
+# | | | |
+# | | | \-> flag telling wether it is
+# | | | fuzzy (F) or not (-)
+# | | |
+# | | \-> line number in the .po file
+# | |
+# | \-> line number in the source file
+# |
+# \-> filename where the original string lies
+#
+#
+# Last four lines will look like :
+# Translated : 23 (23.0%)
+# of which : 2 fuzzy ( 8.6%)
+# Not translated : 77 (77.0%)
+# Total : 100
+#
+#
+# TODO:
+# - Print the fuzzy translated string at the same level as the
+# untranslated one;
+# - basic checks about syntax (missing terminating double quotes);
+# - option for brief mode (only last four lines);
+# - other?
+
+
+BEGIN \
+{
+ count = 0;
+ fuzzy = 0;
+ is_fuzzy = 0;
+ missing = 0;
+ first = 1;
+}
+
+# Is this translation fuzzy? If so count it
+$1 == "#," && $2 ~ /^fuzzy(|,)$/ \
+{
+ fuzzy++;
+ # Next translation will be fuzzy!
+ is_fuzzy = 1;
+}
+
+$1 == "#:" \
+{
+ file = $2;
+}
+
+# Skip the first msgid as it is no true translation
+$1 ~ /msgid/ && first == 1 \
+{
+ first = 0;
+ next;
+}
+
+$1 ~ /msgid/ && first == 0 \
+{
+ # One more translation
+ count++;
+ line = NR;
+
+ # Gets the untranslated string (with double quotes :-( )
+ $1 = "";
+ original = $0;
+ getline;
+ while( $1 != "msgstr" )
+ {
+ original = original $0
+ getline;
+ }
+
+ # Now extract the translated string (with double quotes as well :-( )
+ $1 = "";
+ translation = $0;
+ # In case we have no blank line after the last translation (EOF),
+ # we need to stop this silly loop. Allowing a 10-line message.
+ len = 10;
+ getline;
+ while( $0 != "" && $0 !~ /^#/ && len != 0 )
+ {
+ translation = translation $0
+ getline;
+ len--;
+ }
+
+ # Remove double quotes from multi-line messages and translations
+ msg = ""
+ n = split( original, a, "\"" );
+ # start at 2 to get rid of the preceding space
+ for( i=2; i<=n; i++ )
+ {
+ msg = msg a[i];
+ }
+ trans = "";
+ n = split( translation, a, "\"" );
+ # start at 2 to get rid of the preceding space
+ for( i=2; i<=n; i++ )
+ {
+ trans = trans a[i]
+ }
+
+ # Checks wether we have a translation or not, wether it is fuzzy or not
+ if( ( trans == "" ) || ( is_fuzzy == 1 ) )
+ {
+ # Enclose original messages between double quotes
+ printf( "[%s](%d)", file, line );
+ if( is_fuzzy == 1 )
+ {
+ printf( "F" );
+ }
+ else
+ {
+ printf( "-" );
+ }
+ printf( " \"%s\"\n", msg );
+ if( trans == "" )
+ {
+ missing++;
+ }
+ }
+
+ is_fuzzy = 0;
+}
+
+END \
+{
+ # Lines are longer than 80 chars, but I won't cut them
+ printf( "\n" );
+ printf( "Translated : %4d (%4.1f%%)\n", count-missing, 100.0*(count-missing)/count );
+ printf( " of which : %4d fuzzy (%4.1f%%)\n", fuzzy, 100*fuzzy/(count-missing) );
+ printf( "Not translated : %4d (%4.1f%%)\n", missing, 100.0*missing/count );
+ printf( "Total : %4d\n", count );
+}
diff --git a/tools/check-usb-chip.c b/tools/check-usb-chip.c
new file mode 100644
index 0000000..68b8f79
--- /dev/null
+++ b/tools/check-usb-chip.c
@@ -0,0 +1,4128 @@
+/*
+ check-usb-chip.c -- Find out what USB scanner chipset is used
+
+ Copyright (C) 2003-2005 Henning Meier-Geinitz <henning@meier-geinitz.de>
+ Copyright (C) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
+ for LM983x tests
+ Copyright (C) 2003 Gerard Klaver <gerard at gkall dot hobby dot nl>
+ for ICM532B tests
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+*/
+
+
+#include "../include/sane/config.h"
+
+#ifdef HAVE_LIBUSB
+
+#include "../include/sane/sane.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_LUSB0_USB_H
+#include <lusb0_usb.h>
+#else
+#include <usb.h>
+#endif
+
+#include "../include/_stdint.h"
+
+static int verbose = 0;
+static SANE_Bool no_chipset_access;
+#define TIMEOUT 1000
+
+extern char *check_usb_chip (struct usb_device *dev, int verbosity,
+ SANE_Bool from_file);
+
+static int
+prepare_interface (struct usb_device *dev, usb_dev_handle ** handle)
+{
+ int result;
+
+ if (no_chipset_access)
+ return 0;
+
+ *handle = usb_open (dev);
+ if (*handle == 0)
+ {
+ if (verbose > 1)
+ printf (" Couldn't open device: %s\n", usb_strerror ());
+ return 0;
+ }
+
+ result =
+ usb_set_configuration (*handle, dev->config[0].bConfigurationValue);
+ if (result < 0)
+ {
+ if (verbose > 1)
+ printf (" Couldn't set configuration: %s\n", usb_strerror ());
+ usb_close (*handle);
+ return 0;
+ }
+
+ result = usb_claim_interface (*handle, 0);
+ if (result < 0)
+ {
+ if (verbose > 1)
+ printf (" Couldn't claim interface: %s\n", usb_strerror ());
+ usb_close (*handle);
+ return 0;
+ }
+ return 1;
+}
+
+static void
+finish_interface (usb_dev_handle * handle)
+{
+ usb_release_interface (handle, 0);
+ usb_close (handle);
+}
+
+/* Check for Grandtech GT-6801 */
+static char *
+check_gt6801 (struct usb_device *dev)
+{
+ char req[64];
+ usb_dev_handle *handle;
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for GT-6801 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 1)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6801 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ /* Now we send a control message */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "GT-6801?";
+
+ memset (req, 0, 64);
+ req[0] = 0x2e; /* get identification information */
+ req[1] = 0x01;
+
+ result =
+ usb_control_msg (handle, 0x40, 0x01, 0x2010, 0x3f40, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send write control message (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return 0;
+ }
+ result =
+ usb_control_msg (handle, 0xc0, 0x01, 0x2011, 0x3f00, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send read control message (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return 0;
+ }
+ if (req[0] != 0 || (req[1] != 0x2e && req[1] != 0))
+ {
+ if (verbose > 2)
+ printf (" Unexpected result from control message (%0x/%0x)\n",
+ req[0], req[1]);
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "GT-6801";
+}
+
+/* Check for Grandtech GT-6816 */
+static char *
+check_gt6816 (struct usb_device *dev)
+{
+ char req[64];
+ usb_dev_handle *handle;
+ int result;
+ int i;
+
+ if (verbose > 2)
+ printf (" checking for GT-6816 ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != USB_CLASS_PER_INTERFACE)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6816 (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ if (dev->config[0].bNumInterfaces != 0x01)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bNumInterfaces = 0x%x)\n",
+ dev->config[0].bNumInterfaces);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 2)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6816 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6816 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+
+ }
+
+ /* Now we send a control message */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "GT-6816?";
+
+ memset (req, 0, 64);
+ for (i = 0; i < 8; i++)
+ {
+ req[8 * i + 0] = 0x73; /* check firmware */
+ req[8 * i + 1] = 0x01;
+ }
+
+ result =
+ usb_control_msg (handle, 0x40, 0x04, 0x2012, 0x3f40, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send write control message (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return 0;
+ }
+ result =
+ usb_control_msg (handle, 0xc0, 0x01, 0x2013, 0x3f00, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ /* Before firmware upload, 64 bytes are returned. Some libusb
+ implementations/operating systems can't seem to cope with short
+ packets. */
+ result =
+ usb_control_msg (handle, 0xc0, 0x01, 0x2013, 0x3f00, req, 8, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send read control message (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return 0;
+ }
+ }
+
+ if (req[0] != 0)
+ {
+ if (verbose > 2)
+ printf (" Unexpected result from control message (%0x/%0x)\n",
+ req[0], req[1]);
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "GT-6816";
+}
+
+/* Check for Grandtech GT-8911 */
+static char *
+check_gt8911 (struct usb_device *dev)
+{
+ char req[64];
+ usb_dev_handle *handle;
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for GT-8911 ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != USB_CLASS_PER_INTERFACE)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 1, bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-8911 (check 2, bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 3, bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0x00)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 4, bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 2)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-8911 (check 5, bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ /* Check first endpoint descriptor block */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 6, bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 7, bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+
+ }
+ if (dev->config[0].bNumInterfaces < 2)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-8911 (check 8, bNumInterfaces = %d)\n",
+ dev->config[0].bNumInterfaces);
+ return 0;
+ }
+ if (dev->config[0].interface[1].num_altsetting < 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-8911 (check 9, num_altsetting = %d)\n",
+ dev->config[0].interface[1].num_altsetting);
+ return 0;
+ }
+
+ /* Check fourth endpoint descriptor block */
+ if ((dev->config[0].interface[1].altsetting[2].endpoint[0].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[1].altsetting[2].endpoint[0].
+ bmAttributes != 0x01)
+ || (dev->config[0].interface[1].altsetting[2].endpoint[0].
+ wMaxPacketSize != 0x01d0)
+ || (dev->config[0].interface[1].altsetting[2].endpoint[0].bInterval !=
+ 0x01))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 10, bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[1].altsetting[2].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[1].altsetting[2].endpoint[0].bmAttributes,
+ dev->config[0].interface[1].altsetting[2].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[1].altsetting[2].endpoint[0].bInterval);
+ return 0;
+ }
+ if ((dev->config[0].interface[1].altsetting[2].endpoint[1].
+ bEndpointAddress != 0x04)
+ || (dev->config[0].interface[1].altsetting[2].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[1].altsetting[2].endpoint[1].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[1].altsetting[2].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 11, bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[1].altsetting[2].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[1].altsetting[2].endpoint[1].bmAttributes,
+ dev->config[0].interface[1].altsetting[2].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[1].altsetting[2].endpoint[1].bInterval);
+ return 0;
+
+ }
+
+ /* Now we send a control message */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "GT-8911?";
+
+ memset (req, 0, 8);
+ req[0] = 0x55;
+ req[1] = 0x66;
+
+ result =
+ usb_control_msg (handle, 0xc0, 0x10, 0x41, 0x0000, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 12, couldn't send read control message (%s))\n",
+ strerror (errno));
+ finish_interface (handle);
+ return 0;
+ }
+ result =
+ usb_control_msg (handle, 0xc0, 0x10, 0x05, 0x0000, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-8911 (check 13, couldn't send read control message (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return 0;
+ }
+ /* tested on model hardware version 0xffffffc0, firmware version 0x10)) */
+ if (verbose > 2)
+ printf
+ (" Check 14, control message (hardware version %0x / firmware version %0x)\n",
+ req[0], req[1]);
+
+ finish_interface (handle);
+ return "GT-8911";
+}
+
+/* Check for Mustek MA-1017 */
+static char *
+check_ma1017 (struct usb_device *dev)
+{
+ char req[2];
+ usb_dev_handle *handle;
+ int result;
+ char res;
+
+ if (verbose > 2)
+ printf (" checking for MA-1017 ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != USB_CLASS_PER_INTERFACE)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass !=
+ USB_CLASS_PER_INTERFACE))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1017 (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x100)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1017 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1017 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1017 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1017 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1017 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x82)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1017 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0x01))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1017 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ /* read a register value */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "MA-1017?";
+
+ req[0] = 0x00;
+ req[1] = 0x02 | 0x20;
+ result = usb_bulk_write (handle, 0x01, req, 2, 1000);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1017 (Error during bulk write)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ result = usb_bulk_read (handle, 0x82, &res, 1, 1000);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1017 (Error during bulk read)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ /* Read one byte again to work around a bug in the MA-1017 chipset that
+ appears when an odd number of bytes is read or written. */
+ result = usb_bulk_write (handle, 0x01, req, 2, 1000);
+ result = usb_bulk_read (handle, 0x82, &res, 1, 1000);
+ finish_interface (handle);
+ return "MA-1017";
+}
+
+/* Check for Mustek MA-1015 */
+static char *
+check_ma1015 (struct usb_device *dev)
+{
+ char req[8];
+ usb_dev_handle *handle;
+ int result;
+ unsigned char res;
+
+ if (verbose > 2)
+ printf (" checking for MA-1015 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x100)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 2)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1015 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x08)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1015 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ /* Now we read register 0 to find out if this is really a MA-1015 */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return 0;
+
+ memset (req, 0, 8);
+ req[0] = 33;
+ req[1] = 0x00;
+ result = usb_bulk_write (handle, 0x02, req, 8, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (Error during bulk write)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ result = usb_bulk_read (handle, 0x81, (char *) &res, 1, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (Error during bulk read)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ if (res != 0xa5)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1015 (got 0x%x, expected 0xa5)\n", res);
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "MA-1015";
+}
+
+/* Check for Mustek MA-1509 */
+static char *
+check_ma1509 (struct usb_device *dev)
+{
+ char req[8];
+ char inquiry[0x60];
+ usb_dev_handle *handle;
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for MA-1509 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1509 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x08))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1509 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x08)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0x10))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a MA-1509 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ /* This is a SCSI-over-USB chip, we'll read the inquiry */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "MA-1509?";
+
+ memset (req, 0, 8);
+ req[0] = 0x12;
+ req[1] = 1;
+ req[6] = 0x60;
+
+ result = usb_bulk_write (handle, 0x02, req, 8, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (Error during bulk write)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ memset (inquiry, 0, 0x60);
+ result = usb_bulk_read (handle, 0x81, (char *) inquiry, 0x60, TIMEOUT);
+ if (result != 0x60)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (Error during bulk read: %d)\n",
+ result);
+ finish_interface (handle);
+ return 0;
+ }
+ if ((inquiry[0] & 0x1f) != 0x06)
+ {
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (inquiry [0] = %d)\n", inquiry[0]);
+ finish_interface (handle);
+ return 0;
+ }
+ if (strncmp (inquiry + 8, "SCANNER ", 8) != 0)
+ {
+ inquiry[16] = 0;
+ if (verbose > 2)
+ printf (" this is not a MA-1509 (vendor=%s)\n", inquiry + 8);
+ finish_interface (handle);
+ return 0;
+ }
+ inquiry[36] = 0;
+ if (verbose > 2)
+ printf (" MA-1509 version %s\n", inquiry + 32);
+
+ finish_interface (handle);
+ return "MA-1509";
+}
+
+/********** the lm983x section **********/
+
+static int
+lm983x_wb (usb_dev_handle * handle, unsigned char reg, unsigned char val)
+{
+ unsigned char buf[5];
+ int result;
+
+ buf[0] = 0;
+ buf[1] = reg;
+ buf[2] = 0;
+ buf[3] = 1;
+ buf[4] = val;
+
+ result = usb_bulk_write (handle, 3, (char *) buf, 5, TIMEOUT);
+ if (result != 5)
+ return 0;
+
+ return 1;
+}
+
+static int
+lm983x_rb (usb_dev_handle * handle, unsigned char reg, unsigned char *val)
+{
+ unsigned char buf[5];
+ int result;
+
+ buf[0] = 1;
+ buf[1] = reg;
+ buf[2] = 0;
+ buf[3] = 1;
+
+ result = usb_bulk_write (handle, 3, (char *) buf, 4, TIMEOUT);
+ if (result != 4)
+ return 0;
+
+
+ result = usb_bulk_read (handle, 2, (char *) val, 1, TIMEOUT);
+ if (result != 1)
+ return 0;
+
+ return 1;
+}
+
+static char *
+check_merlin (struct usb_device *dev)
+{
+ unsigned char val;
+ int result;
+ usb_dev_handle *handle;
+
+ if (verbose > 2)
+ printf (" checking for LM983[1,2,3] ...\n");
+
+ /* Check device descriptor */
+ if (((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ && (dev->descriptor.bDeviceClass != 0))
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a LM983x (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if ((dev->descriptor.bcdUSB != 0x110)
+ && (dev->descriptor.bcdUSB != 0x101)
+ && (dev->descriptor.bcdUSB != 0x100))
+ {
+ if (verbose > 2)
+ printf (" this is not a LM983x (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a LM983x (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if ((dev->descriptor.bDeviceProtocol != 0) &&
+ (dev->descriptor.bDeviceProtocol != 0xff))
+ {
+ if (verbose > 2)
+ printf (" this is not a LM983x (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a LM983x (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x1)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x10))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a LM983x (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x82)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ /* Currently disabled as we have some problems in detection here ! */
+ /*|| (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval != 0) */
+ )
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a LM983x (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x40)
+ /* Currently disabled as we have some problems in detection here ! */
+ /* || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval != 0) */
+ )
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a LM983x (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "LM983x?";
+
+ result = lm983x_wb (handle, 0x07, 0x00);
+ if (1 == result)
+ result = lm983x_wb (handle, 0x08, 0x02);
+ if (1 == result)
+ result = lm983x_rb (handle, 0x07, &val);
+ if (1 == result)
+ result = lm983x_rb (handle, 0x08, &val);
+ if (1 == result)
+ result = lm983x_rb (handle, 0x69, &val);
+
+ if (0 == result)
+ {
+ if (verbose > 2)
+ printf (" Couldn't access LM983x registers.\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ finish_interface (handle);
+
+ switch (val)
+ {
+ case 4:
+ return "LM9832/3";
+ break;
+ case 3:
+ return "LM9831";
+ break;
+ case 2:
+ return "LM9830";
+ break;
+ default:
+ return "LM983x?";
+ break;
+ }
+}
+
+/********** the gl646 section **********/
+
+
+static int
+gl646_write_reg (usb_dev_handle * handle, unsigned char reg,
+ unsigned char val)
+{
+ int result;
+
+ result =
+ usb_control_msg (handle, 0x00, 0x00, 0x83, 0x00, (char *) &reg, 0x01,
+ TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ result =
+ usb_control_msg (handle, 0x00, 0x00, 0x85, 0x00, (char *) &val, 0x01,
+ TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ return 1;
+}
+
+static int
+gl646_read_reg (usb_dev_handle * handle, unsigned char reg,
+ unsigned char *val)
+{
+ int result;
+
+ result =
+ usb_control_msg (handle, 0x00, 0x00, 0x83, 0x00, (char *) &reg, 0x01,
+ TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ result =
+ usb_control_msg (handle, 0x80, 0x00, 0x84, 0x00, (char *) val, 0x01,
+ TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ return 1;
+}
+
+
+static char *
+check_gl646 (struct usb_device *dev)
+{
+ unsigned char val;
+ int result;
+ usb_dev_handle *handle;
+
+ if (verbose > 2)
+ printf (" checking for GL646 ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != USB_CLASS_PER_INTERFACE)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass != 0x10))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646 (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x1)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 8))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "GL646?";
+
+ result = gl646_write_reg (handle, 0x38, 0x15);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (writing register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ result = gl646_read_reg (handle, 0x4e, &val);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (reading register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ if (val != 0x15)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (reg 0x4e != reg 0x38)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "GL646";
+}
+
+/* Same as check_gl646, except that sanity check are different. */
+static char *
+check_gl646_hp (struct usb_device *dev)
+{
+ unsigned char val;
+ int result;
+ usb_dev_handle *handle;
+
+ if (verbose > 2)
+ printf (" checking for GL646_HP ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != 0xff)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass != 0xff))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646_HP (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646_HP (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646_HP (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646_HP (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646_HP (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646_HP (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646_HP (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x1)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 8))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646_HP (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "GL646_HP?";
+
+ result = gl646_write_reg (handle, 0x38, 0x15);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646_HP (writing register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ result = gl646_read_reg (handle, 0x4e, &val);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646_HP (reading register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ if (val != 0x15)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646_HP (reg 0x4e != reg 0x38)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ finish_interface (handle);
+
+ return "GL646_HP";
+}
+
+/* check for the combination of gl660 and gl646 */
+static char *
+check_gl660_gl646 (struct usb_device *dev)
+{
+ unsigned char val;
+ int result;
+ usb_dev_handle *handle;
+
+ if (verbose > 2)
+ printf (" checking for GL660+GL646 ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass !=
+ USB_CLASS_PER_INTERFACE))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL660+GL646 (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x200)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL660+GL646 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL660+GL646 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL660+GL646 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL660+GL646 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ ||
+ ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ && (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x200))
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL660+GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ ||
+ ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ && (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x200))
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL660+GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ ||
+ ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x1)
+ && (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x200))
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 8))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL660+GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "GL660+GL646?";
+
+ result = gl646_write_reg (handle, 0x38, 0x15);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL660+GL646 (writing register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ result = gl646_read_reg (handle, 0x4e, &val);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL660+GL646 (reading register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ if (val != 0x15)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL660+GL646 (reg 0x4e != reg 0x38)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "GL660+GL646";
+}
+
+
+/********** the gl841 section **********/
+
+/* the various incarnations could be distinguished by the
+ * bcdDevice entry:
+ * 0x701 --> GL124
+ * 0x700 --> ?
+ * 0x605 --> GL845
+ * 0x603 --> GL847
+ * 0x601 --> GL846
+ * 0x500 --> GL843
+ * 0x300 --> GL842 (perhaps only >= 0x303 ?)
+ * 0x200 --> GL841
+ */
+static char *
+check_gl841 (struct usb_device *dev)
+{
+ unsigned char val;
+ int result;
+ usb_dev_handle *handle;
+
+ if (verbose > 2)
+ printf (" checking for GL84x ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL84x (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x200)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL84x (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL84x (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL84x (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL84x (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40) &&
+ (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x200))
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL84x (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40) &&
+ (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x200))
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL84x (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x1)
+ ||
+ ((dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval != 8)
+ && (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 16)))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL84x (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ result = prepare_interface (dev, &handle);
+ if (!result) {
+ if (dev->descriptor.bcdDevice == 0x702)
+ return "GL124?";
+ if (dev->descriptor.bcdDevice == 0x701)
+ return "GL124?";
+ if (dev->descriptor.bcdDevice >= 0x700)
+ return "GL848+?";
+ if (dev->descriptor.bcdDevice >= 0x603)
+ return "GL847?";
+ if (dev->descriptor.bcdDevice >= 0x600)
+ return "GL846?";
+ if (dev->descriptor.bcdDevice >= 0x500)
+ return "GL845?";
+ if (dev->descriptor.bcdDevice >= 0x400)
+ return "GL843?";
+ if (dev->descriptor.bcdDevice >= 0x300)
+ return "GL842?";
+ else
+ return "GL841?";
+ }
+
+ result = gl646_write_reg (handle, 0x38, 0x15);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL84x (writing register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ result = gl646_read_reg (handle, 0x38, &val);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL84x (reading register failed)\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ if (val != 0x15)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL84x (reg 0x38 != 0x15)\n");
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+
+ if (dev->descriptor.bcdDevice == 0x702)
+ return "GL128";
+ if (dev->descriptor.bcdDevice == 0x701)
+ return "GL124";
+ if (dev->descriptor.bcdDevice >= 0x700)
+ return "GL848+";
+ if (dev->descriptor.bcdDevice >= 0x605)
+ return "GL845";
+ if (dev->descriptor.bcdDevice >= 0x603)
+ return "GL847";
+ if (dev->descriptor.bcdDevice >= 0x600)
+ return "GL846";
+ if (dev->descriptor.bcdDevice >= 0x500)
+ return "GL843";
+ if (dev->descriptor.bcdDevice >= 0x300)
+ return "GL842";
+ return "GL841";
+}
+
+
+/********** the icm532b section version 0.2 **********/
+/* no write and read test registers yet */
+
+static char *
+check_icm532b (struct usb_device *dev)
+{
+ int result;
+ usb_dev_handle *handle;
+
+ if (verbose > 2)
+ printf (" checking for ICM532B ...\n");
+
+ /* Check device descriptor */
+ if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ || (dev->config[0].interface[0].altsetting[0].bInterfaceClass != 0xff))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 1, bDeviceClass = %d, bInterfaceClass = %d)\n",
+ dev->descriptor.bDeviceClass,
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a ICM532B (check 2, bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 3, bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 4, bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 0x01)
+ {
+ if (verbose > 2)
+ printf (" this is not a ICM532B (check 5, bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ /* Check bEndpointAddress */
+ if (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 6, bEndpointAddress = %d)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress);
+ return 0;
+ }
+ /* Check bmAttributes */
+ if (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x01)
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 7, bEndpointAddress = %d)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].bAlternateSetting != 0x00)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 8, bAlternateSetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[1].bAlternateSetting != 0x01)
+ || (dev->config[0].interface[0].altsetting[1].endpoint[0].
+ wMaxPacketSize != 0x100))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 9, bAlternatesetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[1].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[1].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[2].bAlternateSetting != 0x02)
+ || (dev->config[0].interface[0].altsetting[2].endpoint[0].
+ wMaxPacketSize != 0x180))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 10, bAlternatesetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[2].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[2].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[3].bAlternateSetting != 0x03)
+ || (dev->config[0].interface[0].altsetting[3].endpoint[0].
+ wMaxPacketSize != 0x200))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 11, bAlternatesetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[3].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[3].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[4].bAlternateSetting != 0x04)
+ || (dev->config[0].interface[0].altsetting[4].endpoint[0].
+ wMaxPacketSize != 0x280))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 12, bAlternatesetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[4].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[4].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[5].bAlternateSetting != 0x05)
+ || (dev->config[0].interface[0].altsetting[5].endpoint[0].
+ wMaxPacketSize != 0x300))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 13, bAlternatesetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[5].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[5].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[6].bAlternateSetting != 0x06)
+ || (dev->config[0].interface[0].altsetting[6].endpoint[0].
+ wMaxPacketSize != 0x380))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 14, bAlternatesetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[6].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[6].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[7].bAlternateSetting != 0x07)
+ || (dev->config[0].interface[0].altsetting[7].endpoint[0].
+ wMaxPacketSize != 0x3ff))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a ICM532B (check 15, bAlternatesetting = 0x%x, wMaxPacketSize = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[7].bAlternateSetting,
+ dev->config[0].interface[0].altsetting[7].endpoint[0].
+ wMaxPacketSize);
+ return 0;
+ }
+
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "ICM532B?";
+
+ finish_interface (handle);
+ return "ICM532B";
+}
+/* ====================================== end of icm532b ==================*/
+
+
+/* Check for the combination of a PowerVision PV8630 (USB->parport bridge)
+ and National Semiconductor LM9830 */
+static char *
+check_pv8630_lm9830 (struct usb_device *dev)
+{
+ usb_dev_handle *handle;
+ int result;
+ char data;
+
+ if (verbose > 2)
+ printf (" checking for PV8630/LM9830 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != USB_CLASS_PER_INTERFACE)
+ {
+ if (verbose > 2)
+ printf (" this is not a PV8630/LM9830 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x100)
+ {
+ if (verbose > 2)
+ printf (" this is not a PV8630/LM9830 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a PV8630/LM9830 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a PV8630/LM9830 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a PV8630/LM9830 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ /* Endpoint 0 */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a PV8630/LM9830 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+ /* Endpoint 1 */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x82)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a PV8630/LM9830 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+ /* Endpoint 2 */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0x01))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a PV8630/LM9830 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ /* Now we write/read a register (red offset) */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "PV8630/LM9830?";
+
+ result =
+ usb_control_msg (handle, 0x40, 0x01, 0x38, 0x01, NULL, 0, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send write register number (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ result =
+ usb_control_msg (handle, 0x40, 0x01, 0x0f, 0x00, NULL, 0, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send register data (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ result =
+ usb_control_msg (handle, 0x40, 0x01, 0x38, 0x01, NULL, 0, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send read register number (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ result =
+ usb_control_msg (handle, 0xc0, 0x00, 0, 0x00, &data, 1, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read register data (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ if (data != 0x0f)
+ {
+ if (verbose > 2)
+ printf (" Data read != data written (%d/%d)\n", data, 0x0f);
+ finish_interface (handle);
+ return 0;
+ }
+
+ finish_interface (handle);
+ return "PV8630/LM9830";
+}
+
+
+/* Check for Toshiba M011 */
+static char *
+check_m011 (struct usb_device *dev)
+{
+ usb_dev_handle *handle;
+ int result;
+ char data;
+
+ if (verbose > 2)
+ printf (" checking for M011 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC)
+ {
+ if (verbose > 2)
+ printf (" this is not a M011 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x100)
+ {
+ if (verbose > 2)
+ printf (" this is not a M011 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != USB_CLASS_VENDOR_SPEC)
+ {
+ if (verbose > 2)
+ printf (" this is not a M011 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != USB_CLASS_VENDOR_SPEC)
+ {
+ if (verbose > 2)
+ printf (" this is not a M011 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 1)
+ {
+ if (verbose > 2)
+ printf (" this is not a M011 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ /* Endpoint 0 */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x82)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a M011 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ /* Now we write/read a register (red offset) */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "M011?";
+
+ data = 0x63;
+
+ result =
+ usb_control_msg (handle, 0x40, 0x08, 0x34, 0x00, &data, 1, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't write register (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+ data = 0;
+
+ result =
+ usb_control_msg (handle, 0xc0, 0x00, 0x34, 0x00, &data, 1, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read register (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ if (data != 0x63)
+ {
+ if (verbose > 2)
+ printf (" Data read != data written (%d/%d)\n", data, 0x63);
+ finish_interface (handle);
+ return 0;
+ }
+
+ finish_interface (handle);
+ return "M011";
+}
+
+
+/* Check for Realtek rts88xx */
+static int
+rts88xx_read_reg (usb_dev_handle * handle, unsigned char *req, unsigned char *res, int size)
+{
+ int result;
+
+ result =
+ usb_bulk_write (handle, 0x02, (char *)req, 0x04, TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ result =
+ usb_bulk_read (handle, 0x81, (char *)res, size, TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ return 1;
+}
+
+static char *
+check_rts8858c (struct usb_device *dev)
+{
+ unsigned char req[4];
+ unsigned char res[10];
+ usb_dev_handle *handle;
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for rts8858c ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8858c (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8858c (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8858c (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8858c (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8858c (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a rts8858c (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x08)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a rts8858c (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0xFA))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a rts8858c (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ /* Now we read 10 registers */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "rts8858c?";
+
+ memset (req, 0, 4);
+ req[0] = 0x80; /* get registers 0x12-0x1c */
+ req[1] = 0x12;
+ req[2] = 0x00;
+ req[3] = 0x0a;
+
+ result = rts88xx_read_reg(handle,req,res,req[3]);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read registers\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ if (res[1] != 0x03 || res[2] != 0x00)
+ {
+ if (verbose > 2)
+ printf (" Unexpected result from register reading (0x%0x/0x%0x)\n",
+ res[1], res[2]);
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "rts8858c";
+} /* end of rts8858 detection */
+
+static char *
+check_rts88x1 (struct usb_device *dev)
+{
+ unsigned char req[4];
+ unsigned char res[243];
+ usb_dev_handle *handle;
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for rts8801/rts8891 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8801/rts8891 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8801/rts8891 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8801/rts8891 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8801/rts8891 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a rts8801/rts8891 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a rts8801/rts8891 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x08)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a rts8801/rts8891 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0xFA))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a rts8801/rts8891 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ /* Now we read 10 registers */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "rts8801/rts8891?";
+
+ memset (req, 0, 4);
+ req[0] = 0x80; /* get registers 0x00-0xF2 */
+ req[1] = 0x00;
+ req[2] = 0x00;
+ req[3] = 0xf3;
+
+ result = rts88xx_read_reg(handle,req,res,req[3]);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read registers\n");
+ finish_interface (handle);
+ return 0;
+ }
+
+ /* test CCD and link registers */
+ if (res[0xb0] != 0x80 || ((res[0] & 0x0f)!=0x05))
+ {
+ if (verbose > 2)
+ printf (" Unexpected result from register reading (0x%0x/0x%0x)\n",
+ res[0xb0], res[2]);
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "rts8801/rts8891";
+} /* end of rts8801/rts8891 detection */
+
+
+/* Check for Service & Quality SQ113 */
+static char *
+check_sq113 (struct usb_device *dev)
+{
+ usb_dev_handle *handle;
+ int result;
+ unsigned char data;
+ unsigned char buffer[4];
+
+ if (verbose > 2)
+ printf (" checking for SQ113 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x200)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check interface */
+ if (dev->config[0].interface[0].altsetting[0].bInterfaceClass != 255)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bInterfaceClass = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+
+ if (dev->config[0].interface[0].altsetting[0].bInterfaceSubClass != 255)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bInterfaceSubClass = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bInterfaceSubClass);
+ return 0;
+ }
+ if (dev->config[0].interface[0].altsetting[0].bInterfaceProtocol != 255)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bInterfaceProtocol = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bInterfaceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a SQ113 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ /* Endpoint 0 */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x40)
+ && (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x200))
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a SQ113 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ /* Endpoint 1 */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x82)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x40)
+ && (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x200))
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a SQ113 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+ /* Endpoint 2 */
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x1)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0x03))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a SQ113 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ /* Now we read the status register */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "SQ113?";
+
+ buffer [0] = 0x5f;
+ buffer [1] = 0x00;
+ buffer [2] = 0x5f;
+ buffer [3] = 0x00;
+
+ result =
+ usb_control_msg (handle, 0x40, 0x01, 0xb0, 0, (char *) buffer, 4, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't set bank (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ data = 0x00;
+
+ buffer [0] = 0x8b;
+ buffer [1] = data;
+ buffer [2] = 0x8b;
+ buffer [3] = data;
+
+ result =
+ usb_control_msg (handle, 0x40, 0x01, 0xb0, 0, (char *) buffer, 4, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't write register (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ buffer [0] = 0x8b;
+ buffer [1] = 0x8b;
+ buffer [2] = 0x8b;
+ buffer [3] = 0x8b;
+ result =
+ usb_control_msg (handle, 0x40, 0x01, 0x04, 0x8b, (char *) buffer, 4, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't set read register address (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ result =
+ usb_control_msg (handle, 0xc0, 0x01, 0x07, 0, (char *) buffer, 4, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read register (%s)\n",
+ usb_strerror ());
+ finish_interface (handle);
+ return 0;
+ }
+
+ if ((buffer[0] & 0x10) != 0x10)
+ {
+ if (verbose > 2)
+ printf (" Sensor not home? (0x%02x)\n", buffer[0]);
+ finish_interface (handle);
+ return 0;
+ }
+
+ finish_interface (handle);
+ return "SQ113";
+}
+
+/* Check for Realtek RTS8822 chipset*/
+static char *
+check_rts8822 (struct usb_device *dev)
+{
+ char data[2];
+ usb_dev_handle *handle;
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for RTS8822 ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a RTS8822 (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if ((dev->descriptor.bcdUSB != 0x200)&&(dev->descriptor.bcdUSB != 0x110))
+ {
+ if (verbose > 2)
+ printf (" this is not a RTS8822 (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a RTS8822 (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a RTS8822 (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a RTS8822 (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x200)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a RTS8822 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x200)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a RTS8822 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0x0c))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a RTS8822 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ /* Now we read 1 register */
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return "RTS8822?";
+
+ memset (data, 0, 2);
+
+ result =
+ usb_control_msg(handle, 0xc0, 0x04, 0xfe11, 0x100, data, 0x02, TIMEOUT);
+
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send read control message (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return 0;
+ }
+
+ if ((data[0] == 0)&&(data[1] == 0))
+ {
+ if (verbose > 2)
+ printf (" Unexpected result from register 0xfe11 : 0x%0x%0x\n",
+ data[1], data[0]);
+ finish_interface (handle);
+ return 0;
+ }
+ finish_interface (handle);
+ return "RTS8822";
+} /* end of RTS8822 detection */
+
+/* Check for Silitek chipset found in HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 scanners */
+static char *
+check_hp5590 (struct usb_device *dev)
+{
+ usb_dev_handle *handle;
+ int result;
+ uint8_t status;
+ struct usb_ctrl_setup ctrl;
+ uint8_t data[0x32];
+ uint8_t ack;
+ uint8_t *ptr;
+ int next_packet_size;
+ unsigned int len;
+#define HP5590_NAMES "HP4500C/4570C/5500C/5550C/5590/7650"
+
+ if (verbose > 2)
+ printf (" checking for " HP5590_NAMES " chipset ...\n");
+
+ /* Check device descriptor */
+ if (dev->descriptor.bDeviceClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a " HP5590_NAMES " chipset (bDeviceClass = %d)\n",
+ dev->descriptor.bDeviceClass);
+ return 0;
+ }
+ if (dev->descriptor.bcdUSB != 0x200)
+ {
+ if (verbose > 2)
+ printf (" this is not a " HP5590_NAMES " chipset (bcdUSB = 0x%x)\n",
+ dev->descriptor.bcdUSB);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a " HP5590_NAMES " chipset (bDeviceSubClass = 0x%x)\n",
+ dev->descriptor.bDeviceSubClass);
+ return 0;
+ }
+ if (dev->descriptor.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a " HP5590_NAMES " chipset (bDeviceProtocol = 0x%x)\n",
+ dev->descriptor.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (dev->config[0].interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a " HP5590_NAMES " chipset (bNumEndpoints = %d)\n",
+ dev->config[0].interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress != 0x81)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize != 0x200)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a " HP5590_NAMES " chipset (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bmAttributes != 0x02)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize != 0x200)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval !=
+ 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a " HP5590_NAMES " chipset (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress != 0x83)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bmAttributes != 0x03)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize != 0x01)
+ || (dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval !=
+ 0x08))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a " HP5590_NAMES " chipset (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ bEndpointAddress,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bmAttributes,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].
+ wMaxPacketSize,
+ dev->config[0].interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ result = prepare_interface (dev, &handle);
+ if (!result)
+ return NULL;
+
+ /* USB-in-USB command URB - command 0x0012 (init scanner), returns 0x32 bytes */
+ memset (&ctrl, 0, sizeof(ctrl));
+ ctrl.bRequestType = 0xc0;
+ ctrl.bRequest = 0x04;
+ ctrl.wValue = 0x1200;
+ ctrl.wIndex = 0x00;
+ ctrl.wLength = sizeof(data);
+ result = usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR,
+ 0x04, 0x8f, 0x00,
+ (char *) &ctrl, sizeof (ctrl), TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send send USB-in-USB command (%s)\n",
+ strerror (errno));
+ return NULL;
+ }
+
+ /* Get confirmation for USB-in-USB command */
+ result = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR,
+ 0x0c, 0x8e, 0x20,
+ (char *) &status, sizeof(status), TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read USB-in-USB confirmation (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return NULL;
+ }
+
+ /* Check the confirmation received */
+ if (status != 0x01)
+ {
+ if (verbose > 2)
+ printf (" Didn't get correct confirmation for USB-in-USB command "
+ "(needed: 0x01, got: 0x%02x\n",
+ status);
+ finish_interface (handle);
+ return NULL;
+ }
+
+ /* Read data in 8 byte packets */
+ ptr = data;
+ len = sizeof(data);
+ while (len)
+ {
+ next_packet_size = 8;
+ if (len < 8)
+ next_packet_size = len;
+
+ /* Read data packet */
+ result = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR,
+ 0x04, 0x90, 0x00,
+ (char *) ptr, next_packet_size, TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read USB-in-USB data (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return NULL;
+ }
+
+ /* Check if all of the requested data was received */
+ if (result != next_packet_size)
+ {
+ if (verbose > 2)
+ printf (" Incomplete USB-in-USB data received (needed: %u, got: %u)\n",
+ next_packet_size, result);
+ finish_interface (handle);
+ return NULL;
+ }
+
+ ptr += next_packet_size;
+ len -= next_packet_size;
+ }
+
+ /* Acknowledge the whole received data */
+ ack = 0;
+ result = usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR,
+ 0x0c, 0x8f, 0x00,
+ (char *) &ack, sizeof(ack), TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send USB-in-USB data confirmation (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return NULL;
+ }
+
+ /* Get confirmation for acknowledge */
+ result = usb_control_msg (handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR,
+ 0x0c, 0x8e, 0x20,
+ (char *) &status, sizeof(status), TIMEOUT);
+ if (result < 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't read USB-in-USB confirmation for data confirmation (%s)\n",
+ strerror (errno));
+ finish_interface (handle);
+ return NULL;
+ }
+
+ /* Check the confirmation received */
+ if (status != 0x01)
+ {
+ if (verbose > 2)
+ printf (" Didn't get correct confirmation for USB-in-USB command "
+ "(needed: 0x01, got: 0x%02x\n",
+ status);
+ finish_interface (handle);
+ return NULL;
+ }
+
+ /* Check vendor ID */
+ if (memcmp (data+1, "SILITEK", 7) != 0)
+ {
+ if (verbose > 2)
+ printf (" Incorrect product ID received\n");
+ finish_interface (handle);
+ return NULL;
+ }
+
+ finish_interface (handle);
+ return HP5590_NAMES;
+}
+
+char *
+check_usb_chip (struct usb_device *dev, int verbosity, SANE_Bool from_file)
+{
+ char *chip_name = 0;
+
+ verbose = verbosity;
+ no_chipset_access = from_file;
+
+ if (verbose > 2)
+ printf ("\n<trying to find out which USB chip is used>\n");
+
+ chip_name = check_gt6801 (dev);
+
+ if (!chip_name)
+ chip_name = check_gt6816 (dev);
+
+ if (!chip_name)
+ chip_name = check_gt8911 (dev);
+
+ if (!chip_name)
+ chip_name = check_ma1017 (dev);
+
+ if (!chip_name)
+ chip_name = check_ma1015 (dev);
+
+ if (!chip_name)
+ chip_name = check_ma1509 (dev);
+
+ if (!chip_name)
+ chip_name = check_merlin (dev);
+
+ if (!chip_name)
+ chip_name = check_gl646 (dev);
+
+ if (!chip_name)
+ chip_name = check_gl646_hp (dev);
+
+ if (!chip_name)
+ chip_name = check_gl660_gl646 (dev);
+
+ if (!chip_name)
+ chip_name = check_gl841 (dev);
+
+ if (!chip_name)
+ chip_name = check_icm532b (dev);
+
+ if (!chip_name)
+ chip_name = check_pv8630_lm9830 (dev);
+
+ if (!chip_name)
+ chip_name = check_m011 (dev);
+
+ if (!chip_name)
+ chip_name = check_rts8822 (dev);
+
+ if (!chip_name)
+ chip_name = check_rts8858c (dev);
+
+ if (!chip_name)
+ chip_name = check_sq113 (dev);
+
+ if (!chip_name)
+ chip_name = check_hp5590 (dev);
+
+ if (!chip_name)
+ chip_name = check_rts88x1 (dev);
+
+ if (verbose > 2)
+ {
+ if (chip_name)
+ printf ("<This USB chip looks like a %s (result from %s)>\n\n",
+ chip_name, PACKAGE_STRING);
+ else
+ printf ("<Couldn't determine the type of the USB chip (result from %s)>\n\n",
+ PACKAGE_STRING);
+ }
+
+ return chip_name;
+}
+
+#endif /* HAVE_LIBUSB */
+
+#ifdef HAVE_LIBUSB_1_0
+
+#include <libusb.h>
+
+#include "../include/sane/sane.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../include/_stdint.h"
+
+#define TIMEOUT 1000
+
+
+/** @brief detect used chip
+ *
+ * Try to detect the chip used by a device that looks like a scanner by
+ * trying some basic operation like reading/writing registers.
+ * @param dev libusb_device to probe
+ * @param verbosity level of messages verbosity
+ * @param from_file SANE_True if data read from file
+ * @return a string containing the name of the detected scanner chip
+ */
+char *check_usb_chip (int verbosity,
+ struct libusb_device_descriptor desc,
+ libusb_device_handle * hdl,
+ struct libusb_config_descriptor *config0);
+
+static int verbose = 0;
+
+static int
+genesys_write_reg (libusb_device_handle * handle, unsigned char reg,
+ unsigned char val)
+{
+ int result;
+ unsigned char data[2];
+
+ data[0] = reg;
+ data[1] = val;
+
+ result = libusb_control_transfer (handle,
+ 0x40,
+ 0x04, 0x83, 0x00, data, 0x02, TIMEOUT);
+ if (result < 0)
+ return 0;
+ return 1;
+}
+
+static int
+genesys_read_reg (libusb_device_handle * handle, unsigned char reg,
+ unsigned char *val)
+{
+ int result;
+
+ result = libusb_control_transfer (handle,
+ 0x40,
+ 0x0c, 0x83, 0x00, &reg, 0x01, TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ result = libusb_control_transfer (handle,
+ 0xc0,
+ 0x0c, 0x84, 0x00, val, 0x01, TIMEOUT);
+ if (result < 0)
+ return 0;
+
+ return 1;
+}
+
+/** @brief check for genesys GL646 chips
+ *
+ * @param dev libusb device
+ * @param hdl libusb opened handle
+ * @param config0 configuration 0 from get config _descriptor
+ * @return a string with ASIC name, or NULL if not recognized
+ */
+static char *
+check_gl646 (libusb_device_handle * handle,
+ struct libusb_device_descriptor desc,
+ struct libusb_config_descriptor *config0)
+{
+ unsigned char val;
+ int result;
+
+ if (desc.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bcdUSB = 0x%x)\n", desc.bcdUSB);
+ return 0;
+ }
+ if (desc.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bDeviceSubClass = 0x%x)\n",
+ desc.bDeviceSubClass);
+ return 0;
+ }
+ if (desc.bDeviceProtocol != 0)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bDeviceProtocol = 0x%x)\n",
+ desc.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (config0->interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (bNumEndpoints = %d)\n",
+ config0->interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+
+ if ((config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress !=
+ 0x81)
+ || (config0->interface[0].altsetting[0].endpoint[0].bmAttributes !=
+ 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize !=
+ 0x40)
+ || (config0->interface[0].altsetting[0].endpoint[0].bInterval != 0x0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[0].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ if ((config0->interface[0].altsetting[0].endpoint[1].bEndpointAddress !=
+ 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[1].bmAttributes !=
+ 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[1].wMaxPacketSize !=
+ 0x40)
+ || (config0->interface[0].altsetting[0].endpoint[1].bInterval != 0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[1].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[1].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[1].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ if ((config0->interface[0].altsetting[0].endpoint[2].bEndpointAddress !=
+ 0x83)
+ || (config0->interface[0].altsetting[0].endpoint[2].bmAttributes !=
+ 0x03)
+ || (config0->interface[0].altsetting[0].endpoint[2].wMaxPacketSize !=
+ 0x1)
+ || (config0->interface[0].altsetting[0].endpoint[2].bInterval != 8))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GL646 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[2].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[2].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[2].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[2].bInterval);
+ return 0;
+ }
+
+ result = genesys_write_reg (handle, 0x38, 0x15);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (writing register failed)\n");
+ return 0;
+ }
+
+ result = genesys_read_reg (handle, 0x4e, &val);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (reading register failed)\n");
+ return 0;
+ }
+
+ if (val != 0x15)
+ {
+ if (verbose > 2)
+ printf (" this is not a GL646 (reg 0x4e != reg 0x38)\n");
+ return 0;
+ }
+
+ return "GL646";
+}
+
+/** @brief check for gt6801 chip
+ *
+ * @param dev libusb device
+ * @param hdl libusb opened handle
+ * @param config0 configuration 0 from get config _descriptor
+ * @return a string with ASIC name, or NULL if not recognized
+ */
+static char *
+check_gt6801 (libusb_device_handle * handle,
+ struct libusb_device_descriptor desc,
+ struct libusb_config_descriptor *config0)
+{
+ unsigned char req[64];
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for GT-6801 ...\n");
+
+ /* Check device descriptor */
+ if (desc.bDeviceClass != LIBUSB_CLASS_VENDOR_SPEC)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bDeviceClass = %d)\n",
+ desc.bDeviceClass);
+ return 0;
+ }
+ if (desc.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bcdUSB = 0x%x)\n", desc.bcdUSB);
+ return 0;
+ }
+ if (desc.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bDeviceSubClass = 0x%x)\n",
+ desc.bDeviceSubClass);
+ return 0;
+ }
+ if (desc.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bDeviceProtocol = 0x%x)\n",
+ desc.bDeviceProtocol);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (config0->interface[0].altsetting[0].bNumEndpoints != 1)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6801 (bNumEndpoints = %d)\n",
+ config0->interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress != 0x81)
+ || (config0->interface[0].altsetting[0].endpoint[0].bmAttributes != 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize != 0x40)
+ || (config0->interface[0].altsetting[0].endpoint[0].bInterval != 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6801 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[0].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+
+ /* Now we send a control message */
+
+ memset (req, 0, 64);
+ req[0] = 0x2e; /* get identification information */
+ req[1] = 0x01;
+
+ result = libusb_control_transfer (handle, 0x40, 0x01, 0x2010, 0x3f40, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send write control message (%s)\n",
+ strerror (errno));
+ return NULL;
+ }
+ result = libusb_control_transfer (handle, 0xc0, 0x01, 0x2011, 0x3f00, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send read control message (%s)\n",
+ strerror (errno));
+ return NULL;
+ }
+ if (req[0] != 0 || (req[1] != 0x2e && req[1] != 0))
+ {
+ if (verbose > 2)
+ printf (" Unexpected result from control message (%0x/%0x)\n",
+ req[0], req[1]);
+ return NULL;
+ }
+ return "GT-6801";
+}
+
+/** @brief check for gt6816 chip
+ *
+ * @param dev libusb device
+ * @param hdl libusb opened handle
+ * @param config0 configuration 0 from get config _descriptor
+ * @return a string with ASIC name, or NULL if not recognized
+ */
+static char *
+check_gt6816 (libusb_device_handle * handle,
+ struct libusb_device_descriptor desc,
+ struct libusb_config_descriptor *config0)
+{
+ unsigned char req[64];
+ int result,i;
+
+ if (verbose > 2)
+ printf (" checking for GT-6816 ...\n");
+
+ /* Check device descriptor */
+ if ((desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE)
+ || (config0->interface[0].altsetting[0].bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6816 (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ desc.bDeviceClass,
+ config0->interface[0].altsetting[0].bInterfaceClass);
+ return 0;
+ }
+ if (desc.bcdUSB != 0x110)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bcdUSB = 0x%x)\n", desc.bcdUSB);
+ return 0;
+ }
+ if (desc.bDeviceSubClass != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bDeviceSubClass = 0x%x)\n",
+ desc.bDeviceSubClass);
+ return 0;
+ }
+ if (desc.bDeviceProtocol != 0x00)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bDeviceProtocol = 0x%x)\n",
+ desc.bDeviceProtocol);
+ return 0;
+ }
+
+ if (config0->bNumInterfaces != 0x01)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bNumInterfaces = 0x%x)\n",
+ config0->bNumInterfaces);
+ return 0;
+ }
+
+ /* Check endpoints */
+ if (config0->interface[0].altsetting[0].bNumEndpoints != 2)
+ {
+ if (verbose > 2)
+ printf (" this is not a GT-6816 (bNumEndpoints = %d)\n",
+ config0->interface[0].altsetting[0].bNumEndpoints);
+ return 0;
+ }
+ if ((config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress != 0x81)
+ || (config0->interface[0].altsetting[0].endpoint[0].bmAttributes != 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize != 0x40)
+ || (config0->interface[0].altsetting[0].endpoint[0].bInterval != 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6816 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[0].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[0].bInterval);
+ return 0;
+ }
+ if ((config0->interface[0].altsetting[0].endpoint[1].bEndpointAddress != 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[1].bmAttributes != 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[1].wMaxPacketSize != 0x40)
+ || (config0->interface[0].altsetting[0].endpoint[1].bInterval != 0x00))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GT-6816 (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[1].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[1].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[1].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[1].bInterval);
+ return 0;
+ }
+
+ /* Now we send a control message */
+
+ memset (req, 0, 64);
+ for (i = 0; i < 8; i++)
+ {
+ req[8 * i + 0] = 0x73; /* check firmware */
+ req[8 * i + 1] = 0x01;
+ }
+
+ result = libusb_control_transfer (handle, 0x40, 0x04, 0x2012, 0x3f40, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send write control message (%s)\n",
+ strerror (errno));
+ return NULL;
+ }
+ result = libusb_control_transfer (handle, 0xc0, 0x01, 0x2013, 0x3f00, req, 64, TIMEOUT);
+ if (result <= 0)
+ {
+ /* Before firmware upload, 64 bytes are returned. Some libusb
+ implementations/operating systems can't seem to cope with short
+ packets. */
+ result = libusb_control_transfer (handle, 0xc0, 0x01, 0x2013, 0x3f00, req, 8, TIMEOUT);
+ if (result <= 0)
+ {
+ if (verbose > 2)
+ printf (" Couldn't send read control message (%s)\n",
+ strerror (errno));
+ return NULL;
+ }
+ }
+ if (req[0] != 0)
+ {
+ if (verbose > 2)
+ printf (" Unexpected result from control message (%0x/%0x)\n",
+ req[0], req[1]);
+ return NULL;
+ }
+ return "GT-6816";
+}
+
+/** @brief check for known genesys chip
+ *
+ * Try to check if the scanner use a known genesys ASIC.
+ * The various incarnations could be distinguished by the
+ * bcdDevice entry:
+ * 0x701 --> GL124
+ * 0x700 --> ?
+ * 0x605 --> GL845
+ * 0x603 --> GL847
+ * 0x601 --> GL846
+ * 0x500 --> GL843
+ * 0x300 --> GL842 (perhaps only >= 0x303 ?)
+ * 0x200 --> GL841
+ *
+ * @param dev libusb device
+ * @param hdl libusb opened handle
+ * @param config0 configuration 0 from get config _descriptor
+ * @return a string with ASIC name, or NULL if not recognized
+ */
+static char *
+check_genesys (libusb_device_handle * handle,
+ struct libusb_device_descriptor desc,
+ struct libusb_config_descriptor *config0)
+{
+ unsigned char val;
+ int result;
+
+ if (verbose > 2)
+ printf (" checking for GLxxx ...\n");
+
+ /* Check GL646 device descriptor */
+ if ((desc.bDeviceClass == LIBUSB_CLASS_PER_INTERFACE)
+ && (config0->interface[0].altsetting[0].bInterfaceClass == 0x10))
+ {
+ return check_gl646 (handle, desc, config0);
+ }
+ if (verbose > 2)
+ {
+ printf
+ (" this is not a GL646 (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ desc.bDeviceClass,
+ config0->interface[0].altsetting[0].bInterfaceClass);
+ }
+
+ /* Check device desc */
+ if ((desc.bDeviceClass != LIBUSB_CLASS_VENDOR_SPEC)
+ || (config0->interface[0].altsetting[0].bInterfaceClass !=
+ LIBUSB_CLASS_VENDOR_SPEC))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GLxxx (bDeviceClass = %d, bInterfaceClass = %d)\n",
+ desc.bDeviceClass,
+ config0->interface[0].altsetting[0].bInterfaceClass);
+ return NULL;
+ }
+
+ if (desc.bDeviceSubClass != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GLxxx (bDeviceSubClass = 0x%x)\n",
+ desc.bDeviceSubClass);
+ return NULL;
+ }
+ if (desc.bDeviceProtocol != 0xff)
+ {
+ if (verbose > 2)
+ printf (" this is not a GLxxx (bDeviceProtocol = 0x%x)\n",
+ desc.bDeviceProtocol);
+ return NULL;
+ }
+
+ /* Check endpoints */
+ if (config0->interface[0].altsetting[0].bNumEndpoints != 3)
+ {
+ if (verbose > 2)
+ printf (" this is not a GLxxx (bNumEndpoints = %d)\n",
+ config0->interface[0].altsetting[0].bNumEndpoints);
+ return NULL;
+ }
+
+ if ((config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress !=
+ 0x81)
+ || (config0->interface[0].altsetting[0].endpoint[0].bmAttributes !=
+ 0x02)
+ ||
+ ((config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize !=
+ 0x40)
+ && (config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize !=
+ 0x200))
+ || (config0->interface[0].altsetting[0].endpoint[0].bInterval != 0x0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GLxxx (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[0].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[0].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[0].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[0].bInterval);
+ return NULL;
+ }
+
+ if ((config0->interface[0].altsetting[0].endpoint[1].bEndpointAddress !=
+ 0x02)
+ || (config0->interface[0].altsetting[0].endpoint[1].bmAttributes !=
+ 0x02)
+ ||
+ ((config0->interface[0].altsetting[0].endpoint[1].wMaxPacketSize !=
+ 0x40)
+ && (config0->interface[0].altsetting[0].endpoint[1].wMaxPacketSize !=
+ 0x200))
+ || (config0->interface[0].altsetting[0].endpoint[1].bInterval != 0))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GLxxx (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[1].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[1].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[1].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[1].bInterval);
+ return NULL;
+ }
+
+ if ((config0->interface[0].altsetting[0].endpoint[2].bEndpointAddress !=
+ 0x83)
+ || (config0->interface[0].altsetting[0].endpoint[2].bmAttributes !=
+ 0x03)
+ || (config0->interface[0].altsetting[0].endpoint[2].wMaxPacketSize !=
+ 0x1)
+ || ((config0->interface[0].altsetting[0].endpoint[2].bInterval != 8)
+ && (config0->interface[0].altsetting[0].endpoint[2].bInterval !=
+ 16)))
+ {
+ if (verbose > 2)
+ printf
+ (" this is not a GLxxx (bEndpointAddress = 0x%x, bmAttributes = 0x%x, "
+ "wMaxPacketSize = 0x%x, bInterval = 0x%x)\n",
+ config0->interface[0].altsetting[0].endpoint[2].bEndpointAddress,
+ config0->interface[0].altsetting[0].endpoint[2].bmAttributes,
+ config0->interface[0].altsetting[0].endpoint[2].wMaxPacketSize,
+ config0->interface[0].altsetting[0].endpoint[2].bInterval);
+ return NULL;
+ }
+
+ /* write then read a register using common read/write control message */
+ result = genesys_write_reg (handle, 0x38, 0x15);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GLxxx (writing register failed)\n");
+ return NULL;
+ }
+
+ result = genesys_read_reg (handle, 0x38, &val);
+ if (!result)
+ {
+ if (verbose > 2)
+ printf (" this is not a GLxxx (reading register failed)\n");
+ return NULL;
+ }
+
+ if (val != 0x15)
+ {
+ if (verbose > 2)
+ printf (" this is not a GLxxx (reg 0x38 != 0x15)\n");
+ return NULL;
+ }
+
+ /* decide revision number based on bcdUsb heuristics */
+ if (desc.bcdDevice == 0x702)
+ return "GL128";
+ if (desc.bcdDevice == 0x701)
+ return "GL124";
+ if (desc.bcdDevice >= 0x700)
+ return "GL848+";
+ if (desc.bcdDevice >= 0x605)
+ return "GL845";
+ if (desc.bcdDevice >= 0x603)
+ return "GL847";
+ if (desc.bcdDevice >= 0x600)
+ return "GL846";
+ if (desc.bcdDevice >= 0x500)
+ return "GL843";
+ if (desc.bcdDevice >= 0x300)
+ return "GL842";
+ if (desc.bcdDevice > 0x101)
+ return "GL841";
+ return "GL646_HP";
+}
+
+char *
+check_usb_chip (int verbosity,
+ struct libusb_device_descriptor desc,
+ libusb_device_handle * hdl,
+ struct libusb_config_descriptor *config0)
+{
+ char *chip_name = NULL;
+ int ret;
+
+ verbose = verbosity;
+
+ if (verbose > 2)
+ printf ("\n<trying to find out which USB chip is used>\n");
+
+ /* set config if needed */
+ if (desc.bNumConfigurations > 1)
+ {
+ ret = libusb_set_configuration (hdl, config0->bConfigurationValue);
+ if (ret < 0)
+ {
+ if (verbose > 2)
+ printf ("couldnt set device to configuration %d\n",
+ config0->bConfigurationValue);
+ return NULL;
+ }
+ }
+
+ /* claim the interface (only interface 0 is currently handled */
+ ret = libusb_claim_interface (hdl, 0);
+ if (ret < 0)
+ {
+ if (verbose > 2)
+ printf ("could not claim USB device interface\n");
+ return NULL;
+ }
+
+ /* now USB is opened and set up, actual chip detection */
+
+ if (!chip_name)
+ chip_name = check_gt6801 (hdl, desc, config0);
+
+ if (!chip_name)
+ chip_name = check_gt6816 (hdl, desc, config0);
+
+ if (!chip_name)
+ chip_name = check_genesys (hdl, desc, config0);
+
+ if (verbose > 2)
+ {
+ if (chip_name)
+ printf ("<This USB chip looks like a %s (result from %s)>\n\n",
+ chip_name, PACKAGE_STRING);
+ else
+ printf
+ ("<Couldn't determine the type of the USB chip (result from %s)>\n\n",
+ PACKAGE_STRING);
+ }
+
+ /* close USB device */
+ libusb_release_interface (hdl, 0);
+ return chip_name;
+}
+#endif /* HAVE_LIBUSB_1_0 */
diff --git a/tools/gamma4scanimage.c b/tools/gamma4scanimage.c
new file mode 100644
index 0000000..69d83c7
--- /dev/null
+++ b/tools/gamma4scanimage.c
@@ -0,0 +1,140 @@
+/* --------------------------------------------------------------------------------------------------------- */
+/* sane - Scanner Access Now Easy.
+
+ gamma4scanimage
+
+ (C) 2002 Oliver Rauch
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+*/
+/* --------------------------------------------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ double gamma = 1.0;
+ int maxin = 16383; /* 14 bit gamma input */
+ int maxout = 255; /* 8 bit gamma output */
+ int shadow = 0;
+ int highlight = maxin;
+ int in, out;
+ float f;
+
+ if ( (argc==1) || (argc>6) )
+ {
+ printf("Usage: %s gamma [shadow [highlight [maxin [maxout]]]]\n", argv[0]);
+ exit(-1);
+ }
+
+ if (argc>1)
+ {
+ gamma = atof(argv[1]);
+ }
+
+ if (argc>2)
+ {
+ shadow = atoi(argv[2]);
+ }
+
+ if (argc>3)
+ {
+ highlight = atoi(argv[3]);
+ }
+
+ if (argc>4)
+ {
+ maxin = atoi(argv[4]);
+ }
+
+ if (argc>5)
+ {
+ maxout = atoi(argv[5]);
+ }
+
+ if (shadow < 0)
+ {
+ printf("%s error: shadow=%d < 0\n", argv[0], shadow);
+ exit(-1);
+ }
+
+ if (highlight < 0)
+ {
+ printf("%s error: highlight=%d < 0\n", argv[0], highlight);
+ exit(-1);
+ }
+
+ if (maxin < 0)
+ {
+ printf("%s error: maxin=%d < 0\n", argv[0], maxin);
+ exit(-1);
+ }
+
+ if (maxout < 0)
+ {
+ printf("%s error: maxout=%d < 0\n", argv[0], maxout);
+ exit(-1);
+ }
+
+ if (shadow >= highlight)
+ {
+ printf("%s error: shadow=%d >= highlight=%d\n", argv[0], shadow, highlight);
+ exit(-1);
+ }
+
+ if (highlight > maxin)
+ {
+ printf("%s error: highlight=%d > maxin=%d\n", argv[0], highlight, maxin);
+ exit(-1);
+ }
+
+ if ((gamma < 0.1) || (gamma > 5))
+ {
+ printf("%s error: gamma=%f out of range [0.1;5]\n", argv[0], gamma);
+ exit(-1);
+ }
+
+ f = (highlight - shadow) / 255.0 + shadow;
+
+ printf("[%d]%d-", 0, 0);
+
+ if (shadow > 0)
+ {
+ printf("[%d]%d-", shadow, 0);
+ }
+
+ while (f < highlight)
+ {
+ in = (int) f;
+ out = maxout * pow((double) (in - shadow)/(highlight-shadow), (1.0/gamma));
+ printf("[%d]%d-", in, out);
+ f *= 1.5;
+ }
+
+ if (f > highlight)
+ {
+ printf("[%d]%d-", highlight, maxout);
+ }
+
+ printf("[%d]%d", maxin, maxout);
+
+ return 0;
+}
diff --git a/tools/hotplug-ng/README b/tools/hotplug-ng/README
new file mode 100644
index 0000000..1a17a19
--- /dev/null
+++ b/tools/hotplug-ng/README
@@ -0,0 +1,46 @@
+hotplug/hotplug-ng hook for sane-backends
+-----------------------------------------
+
+The libsane.hotplug script is intended to replace the existing hotplug scripts,
+as those won't be usable with the new hotplug-ng. The libsane.hotplug script
+works with both hotplug and hotplug-ng. For current Linux kernels, "udev" is
+state of the art, see the "udev" directory instead.
+
+This script is provided in the hope that it will be useful, simpler, faster and
+more extensible than the current usermap approach.
+
+
+INSTALLATION
+------------
+
+Install libsane.hotplug in /etc/hotplug/usb, and make it executable.
+
+Create the directory /etc/sane.d/hotplug and copy libsane.db there.
+
+
+FILE FORMAT
+-----------
+
+The libsane.db contains 5 tab-separated fields:
+
+0xVVVV<tab>0xPPPP<tab>root:scanner<tab>0660<tab>optional_script
+
+Fields:
+ - vendor ID
+ - product ID
+ - ownership (user:group)
+ - permissions
+ - path of an optional script to run (it can be omitted)
+
+
+USAGE
+-----
+
+When run by hotplug/hotplug-ng, the libsane.hotplug script will grep for
+^0xVVVV[[:space:]]0xPPPP in /etc/sane.d/hotplug/*.db. If a match is found,
+the settings are applied to the device.
+
+The optional script is then run; this script can access the environment
+variables set by hotplug/hotplug-ng (see the documentation). The libsane.hotplug
+script will also set and export the DEVVID and DEVPID variables, containing the
+vendor and device ID of the scanner (of the form VVVV and PPPP).
diff --git a/tools/hotplug-ng/libsane.hotplug b/tools/hotplug-ng/libsane.hotplug
new file mode 100755
index 0000000..dec38a5
--- /dev/null
+++ b/tools/hotplug-ng/libsane.hotplug
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# This file is part of the SANE distribution.
+# Hotplug USB hook for SANE
+
+if [ "$ACTION" != "add" ]; then
+ exit 0
+fi
+
+DEVVID=$(printf %4s $(echo $PRODUCT | cut -d'/' -f1) | tr ' ' 0)
+DEVPID=$(printf %4s $(echo $PRODUCT | cut -d'/' -f2) | tr ' ' 0)
+
+DEVCONF=$(grep -i "^0x$DEVVID[[:space:]]\+0x$DEVPID" /etc/sane.d/hotplug/*.db 2> /dev/null)
+
+if [ $? != 0 ]; then
+ exit 0
+fi
+
+set $DEVCONF
+
+chown $3 $DEVICE && chmod $4 $DEVICE
+
+if [ ! -z $5 -a -x $5 ]; then
+ export DEVVID
+ export DEVPID
+ exec $5
+fi
+
+exit 0
diff --git a/tools/hotplug/README b/tools/hotplug/README
new file mode 100644
index 0000000..1170639
--- /dev/null
+++ b/tools/hotplug/README
@@ -0,0 +1,35 @@
+README for the USB hotplug scripts for sane-backends :
+------------------------------------------------------
+
+If you intend to use a USB scanner with libusb and older versions of Linux, you
+should install the hotplug package, and then take the following steps. For
+current Linux kernels, "udev" is state of the art, see the "udev" directory
+instead.
+
+ o Copy the libsane.usermap and libusbscanner files from this directory to
+ /etc/hotplug/usb/
+ o If you use Linux 2.6.3 or older, add scanner to /etc/hotplug/blacklist so
+ that the scanner.o kernel driver won't be loaded by hotplug. With later
+ kernel versions there is no scanner module and therefore it's not necessary
+ to use the blacklist.
+ o Check if /etc/hotplug/usb/libsane.usermap already knows about your scanner.
+ If your scanner is not in this list,add a line similar to the other ones
+ using the vendor ID and the product ID of your scanner. Please contact the
+ sane-devel mailing list in this case so the ids of your scanner can be added.
+ o Make sure that the "scanner" group exists on your system and that every user
+ who should be allowed to acces the scanner is a member of that group.
+ Alternatively, you can enable access for every user of your system in
+ libusbscanner.
+
+The vendor ID and product ID of your scanner can be obtained by running
+sane-find-scanner (you might need to run it as root).
+
+Please note that the scanner.o (or scanner.ko in Linux 2.6) kernel module is
+now deprecated and marked as obsolete in Linux 2.6. It is recommended to switch
+to libusb.
+
+If the hotplug support doesn't work for you once you have taken the steps
+described above, check that your kernel has been built with hotplug support.
+Otherwise, you'll need to rebuild your kernel.
+
+ -- Julien BLACHE <jb@jblache.org>, Sat, 28 Feb 2004 10:01:02 +0000
diff --git a/tools/hotplug/libusbscanner b/tools/hotplug/libusbscanner
new file mode 100755
index 0000000..bf613a5
--- /dev/null
+++ b/tools/hotplug/libusbscanner
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# This file is part of sane-backends.
+#
+# This script changes the permissions and ownership of a USB device under
+# /proc/bus/usb to grant access to this device to users in the scanner group.
+#
+# Ownership is set to root:scanner, permissions are set to 0660.
+#
+# Arguments :
+# -----------
+# ACTION=[add|remove]
+# DEVICE=/proc/bus/usb/BBB/DDD
+# TYPE=usb
+
+# latest hotplug doesn't set DEVICE on 2.6.x kernels
+if [ -z "$DEVICE" ] ; then
+ IF=`echo $DEVPATH | sed 's/\(bus\/usb\/devices\/\)\(.*\)-\(.*\)/\2/'`
+ DEV=$(cat /sys/${DEVPATH}/devnum)
+ DEVICE=`printf '/proc/bus/usb/%.03d/%.03d' $IF $DEV`
+fi
+
+if [ "$ACTION" = "add" -a "$TYPE" = "usb" ]; then
+ chown root:scanner "$DEVICE"
+ chmod 0660 "$DEVICE"
+fi
+
+
+# That's an insecure but simple alternative
+# Everyone has access to the scanner
+
+# if [ "$ACTION" = "add" -a "$TYPE" = "usb" ]; then
+# chmod 0666 "$DEVICE"
+# fi
+
diff --git a/tools/libtool-get-dll-ext b/tools/libtool-get-dll-ext
new file mode 100755
index 0000000..722e676
--- /dev/null
+++ b/tools/libtool-get-dll-ext
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Author: Petter Reinholdtsen <pere@td.org.uit.no>
+# Date: 2000-03-18
+#
+# Given a libtool lib*.la, return the dll extention used (ie. so, sl,
+# dll, etc)
+if test "x$1" = x; then
+ echo "usage: $0 <libfile.la>"
+ exit 1
+fi
+
+lafile=$1
+
+libnames=`grep library_names= $lafile`
+last=`echo $libnames | cut -d\' -f2|tr " " "\n"|tail -n 1`
+dllend=`echo $last | cut -d. -f2`
+
+echo $dllend
diff --git a/tools/mustek600iin-off.c b/tools/mustek600iin-off.c
new file mode 100644
index 0000000..d2c6754
--- /dev/null
+++ b/tools/mustek600iin-off.c
@@ -0,0 +1,199 @@
+/*
+ off.c - Switch the Mustek 600 II N off
+
+ This utility accesses the I/O-ports directly and must therefore be
+ run with euid root, or must at least have access to /dev/port.
+ Compile with:
+ gcc -DHAVE_SYS_IO_H -O2 -Wall -s -o off off.c
+ The -O2 optimization is needed to allow inline functions !
+ Copyright (C) 1997-1999 Andreas Czechanowski, DL4SDC
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ andreas.czechanowski@ins.uni-stuttgart.de
+ */
+
+#include "../include/sane/config.h"
+#include "../include/sane/sanei.h"
+
+#define MUSTEK_CONF STRINGIFY(PATH_SANE_CONFIG_DIR) "/mustek.conf"
+#define PORT_DEV "/dev/port"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_IO_H
+# include <sys/io.h> /* use where available (glibc 2.x, for example) */
+#elif HAVE_ASM_IO_H
+# include <asm/io.h> /* ugly, but backwards compatible */
+#elif defined(__i386__) && defined (__GNUC__)
+
+static __inline__ void
+outb (u_char value, u_long port)
+{
+ __asm__ __volatile__ ("outb %0,%1"::"a" (value), "d" ((u_short) port));
+}
+
+static __inline__ u_char
+inb (u_long port)
+{
+ u_char value;
+
+ __asm__ __volatile__ ("inb %1,%0":"=a" (value):"d" ((u_short) port));
+ return value;
+}
+#endif
+
+char *Mustek_Conf = MUSTEK_CONF;
+
+int allowed_ports[] =
+{
+ 0x26b, 0x26c,
+ 0x2ab, 0x2ac,
+ 0x2eb, 0x2ec,
+ 0x22b, 0x22c,
+ 0x32b, 0x32c,
+ 0x36b, 0x36c,
+ 0x3ab, 0x3ac,
+ 0x3eb, 0x3ec,
+ -1
+};
+
+void
+usage (void)
+{
+ fprintf (stderr, "Usage: off [port]\n"
+ " switches the Mustek 600 II N off that is connected to\n"
+ " base address <port>. If address is not given, reads it\n"
+ " from SANE config file <%s>.\n", Mustek_Conf);
+}
+
+void
+noaccess (int portaddr)
+{
+ fprintf (stderr, "Access to port 0x%03x not allowed !\n", portaddr);
+}
+
+int
+check_port (int portaddr)
+{
+ int i, j;
+
+ for (i = 0; (j = allowed_ports[i]) != -1; i++)
+ {
+ if (j == portaddr)
+ return j;
+ }
+ return -1;
+}
+
+int
+str2int (char *ch)
+{
+ int i;
+
+ i = strtol (ch, NULL, 0);
+ return i;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *cp;
+ int portaddr = 0;
+ FILE *fp;
+ int pfd;
+
+ /* get config file name from environment if variable is set */
+ if (NULL != (cp = getenv ("MUSTEK_CONF")))
+ {
+ Mustek_Conf = cp;
+ }
+
+ /* if port is explicitly given, try this one */
+ if (argc > 1)
+ {
+ portaddr = str2int (argv[1]);
+ }
+ /* else try to look it up from SANE's mustek.conf file */
+ else if (NULL != (fp = fopen (MUSTEK_CONF, "r")))
+ {
+ char line[256];
+
+ while (NULL != fgets (line, 255, fp))
+ {
+ if ('#' == *line)
+ continue;
+ if (0 != (portaddr = str2int (line)))
+ break;
+ }
+ fclose (fp);
+ }
+ else
+ {
+ fprintf (stderr, "Mustek config file <%s> not found\n", Mustek_Conf);
+ usage ();
+ exit (1);
+ }
+
+ if (check_port (portaddr) < 0 || check_port (portaddr + 1) < 0)
+ {
+ fprintf (stderr, "invalid port address specified !\n");
+ usage ();
+ exit (1);
+ }
+
+ /* we need the control port, not the data port, so... */
+ portaddr++;
+
+ fprintf (stderr, "using control port address 0x%03x\n", portaddr);
+ /* try to get I/O permission from the kernel */
+ if (ioperm (portaddr, 1, 1) == 0)
+ {
+ outb (0x00, portaddr);
+ }
+ /* else try to open /dev/port to access the I/O port */
+ else if ((pfd = open (PORT_DEV, O_RDWR, 0666)) >= 0)
+ {
+ char offcmd[] =
+ {0x00};
+
+ if ((lseek (pfd, portaddr, SEEK_SET) != portaddr)
+ || (write (pfd, offcmd, 1) != 1))
+ {
+ perror ("error handling /dev/port");
+ exit (1);
+ }
+ close (pfd);
+ }
+ else
+ {
+ fprintf (stderr, "Could not get port access:\n"
+ "Neither via ioperm(), nor via /dev/port.\n"
+ "This program must be run setuid root,\n"
+ "or the user must have access to /dev/port.\n");
+ exit (1);
+ }
+ printf ("successfully sent OFF-command to control port at 0x%03x.\n",
+ portaddr);
+
+ exit (0);
+}
diff --git a/tools/openbsd/attach b/tools/openbsd/attach
new file mode 100755
index 0000000..b6c98c8
--- /dev/null
+++ b/tools/openbsd/attach
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+DEVCLASS=$1
+DEVNAME=$2
+
+case $DEVCLASS in
+0)
+ # generic devices
+ case "$DEVNAME" in
+ ugen*)
+ BUSNAME=`usbdevs -v -d | egrep "Controller|$DEVNAME\$" | grep -B 1 ugen0$ | head -n 1 | sed -e 's,Controller ,,' -e 's,:$,,' `
+ echo $BUSNAME > /var/run/${DEVNAME}.bus
+ # probably our scanner
+ chgrp usb /dev/"$DEVNAME".*
+ chgrp usb /dev/"$BUSNAME"
+ ;;
+ esac
+
+ ;;
+esac
diff --git a/tools/openbsd/detach b/tools/openbsd/detach
new file mode 100755
index 0000000..a5c209c
--- /dev/null
+++ b/tools/openbsd/detach
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+DEVCLASS=$1
+DEVNAME=$2
+
+case $DEVCLASS in
+0)
+ # generic devices
+ case "$DEVNAME" in
+ ugen*)
+ BUSNAME=`cat /var/run/${DEVNAME}.bus`
+ rm -f /var/run/${DEVNAME}.bus
+ # probably our scanner
+ chgrp wheel /dev/"$DEVNAME".*
+ if [ x$BUSNAME != x ] ; then
+ chgrp wheel /dev/"$BUSNAME"
+ fi
+ ;;
+ esac
+
+ ;;
+esac
diff --git a/tools/sane-backends.pc.in b/tools/sane-backends.pc.in
new file mode 100644
index 0000000..b4d9731
--- /dev/null
+++ b/tools/sane-backends.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+ldflags=@LDFLAGS@ @GPHOTO2_LDFLAGS@
+libs=@LIBS@ @DL_LIBS@ @LIBV4L_LIBS@ @MATH_LIB@ @TIFF_LIBS@ @JPEG_LIBS@ @GPHOTO2_LIBS@ @SOCKET_LIBS@ @AVAHI_LIBS@ @USB_LIBS@ @SCSI_LIBS@ @RESMGR_LIBS@
+
+Name: SANE Backends
+Description: Backends for SANE, the universal scanner interface
+Version: @VERSION@
+Requires:
+Libs: -L${libdir} -lsane
+Libs.private: ${ldflags} ${libs}
+Cflags: -I${includedir}
diff --git a/tools/sane-config.in b/tools/sane-config.in
new file mode 100644
index 0000000..8e4b52a
--- /dev/null
+++ b/tools/sane-config.in
@@ -0,0 +1,91 @@
+#!/bin/sh
+#
+# This script is part of SANE, <URL:http://www.sane-project.org/>
+#
+# Send bugreports and other requests to sane-devel@lists.alioth.debian.org
+
+PACKAGE="@PACKAGE@"
+scriptname="sane-config"
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+
+# using our installed *.pc only - neither default nor user paths
+export PKG_CONFIG_LIBDIR="@libdir@/pkgconfig"
+export PKG_CONFIG_PATH=""
+
+pkgconfig_package=sane-backends
+
+usage ()
+{
+ echo "Usage: " 1>&2
+ echo "$scriptname --version - show installed script and SANE version" 1>&2
+ echo "$scriptname --ldflags - linker flags required to link with SANE" 1>&2
+ echo "$scriptname --libs - libraries required to link with SANE" 1>&2
+ echo "$scriptname --cflags - compiler flags required to find SANE headers" 1>&2
+ echo "$scriptname --help - show usage info (this message) " 1>&2
+ echo "$scriptname --help SUBCOMMAND - show help for SUBCOMMAND " 1>&2
+ echo "$scriptname --prefix - prefix used during SANE compile" 1>&2
+ echo "$scriptname --exec-prefix - exec-prefix used during SANE compile" 1>&2
+}
+
+if test $# -eq 0; then
+ usage
+ exit 1
+fi
+
+if test $# -gt 0; then
+ case $1 in
+ --version)
+ echo @NUMBER_VERSION@
+ ;;
+ --help)
+ if test $# -eq 1; then
+ usage
+ elif test $# -eq 2; then
+ case $2 in
+ --cflags)
+ echo "Usage: $0 --cflags"
+ echo " Print C compiler flags for compiling code that uses SANE."
+ echo " This includes any \`-I' flags needed to find Sane's header files."
+ ;;
+ --ldflags)
+ echo "Usage: $0 --ldflags"
+ echo " Print linker flags for building the \`$PACKAGE' executable."
+ echo " Print the linker command-line flags necessary to link against"
+ echo " the SANE library. The libraries are listed with --libs."
+ ;;
+ --libs)
+ echo "Usage: $0 --libs"
+ echo " Print linker flags for building the \`$PACKAGE' executable."
+ echo " Print the linker command-line flags necessary to link against"
+ echo " the SANE library, and any other libraries it requires."
+ ;;
+ esac
+ else
+ usage
+ fi
+ exit 1
+ ;;
+ --ldflags)
+ pkg-config --libs-only-L "$pkgconfig_package"
+ ;;
+ --libs)
+ pkg-config --libs "$pkgconfig_package"
+ ;;
+ --cflags)
+ pkg-config --cflags "$pkgconfig_package"
+ ;;
+ --prefix)
+ echo "${prefix}"
+ ;;
+ --exec-prefix)
+ echo "${exec_prefix}"
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+ esac
+fi
+
diff --git a/tools/sane-desc.c b/tools/sane-desc.c
new file mode 100644
index 0000000..3cc4407
--- /dev/null
+++ b/tools/sane-desc.c
@@ -0,0 +1,4056 @@
+/*
+ sane-desc.c -- generate list of supported SANE devices
+
+ Copyright (C) 2002-2006 Henning Meier-Geinitz <henning@meier-geinitz.de>
+ Copyright (C) 2004 Jose Gato <jgato@gsyc.escet.urjc.es> (XML output)
+ Copyright (C) 2006 Mattias Ellert <mattias.ellert@tsl.uu.se> (plist output)
+ Copyright (C) 2009 Dr. Ing. Dieter Jurzitza <dieter.jurzitza@t-online.de>
+ Copyright (C) 2013 Tom Gundersen <teg@jklm.no> (hwdb output)
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+*/
+
+#include <../include/sane/config.h>
+
+#include "lgetopt.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "../include/sane/sane.h"
+#include "../include/sane/sanei.h"
+#include "../include/sane/sanei_config.h"
+
+#define SANE_DESC_VERSION "3.5"
+
+#define MAN_PAGE_LINK "http://www.sane-project.org/man/%s.5.html"
+#define COLOR_MINIMAL "\"#B00000\""
+#define COLOR_BASIC "\"#FF9000\""
+#define COLOR_GOOD "\"#90B000\""
+#define COLOR_COMPLETE "\"#007000\""
+#define COLOR_UNTESTED "\"#0000B0\""
+#define COLOR_UNSUPPORTED "\"#F00000\""
+#define COLOR_NEW "\"#F00000\""
+#define COLOR_UNKNOWN "\"#000000\""
+
+#define DEVMODE "0664"
+#define DEVOWNER "root"
+#define DEVGROUP "scanner"
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+#define DBG_ERR current_debug_level = 0; debug_call
+#define DBG_WARN current_debug_level = 1; debug_call
+#define DBG_INFO current_debug_level = 2; debug_call
+#define DBG_DBG current_debug_level = 3; debug_call
+
+typedef enum output_mode
+{
+ output_mode_ascii = 0,
+ output_mode_xml,
+ output_mode_html_backends,
+ output_mode_html_backends_split,
+ output_mode_html_mfgs,
+ output_mode_statistics,
+ output_mode_usermap,
+ output_mode_db,
+ output_mode_udev,
+ output_mode_udevacl,
+ output_mode_udevhwdb,
+ output_mode_hwdb,
+ output_mode_plist,
+ output_mode_hal,
+ output_mode_halnew
+}
+output_mode;
+
+typedef enum parameter_type
+{
+ param_none = 0,
+ param_string,
+ param_two_strings,
+ param_three_strings
+}
+parameter_type;
+
+typedef enum status_entry
+{
+ status_unknown,
+ status_unsupported,
+ status_untested,
+ status_minimal,
+ status_basic,
+ status_good,
+ status_complete
+}
+status_entry;
+
+typedef enum device_type
+{
+ type_unknown,
+ type_scanner,
+ type_stillcam,
+ type_vidcam,
+ type_meta,
+ type_api
+}
+device_type;
+
+typedef enum level
+{
+ level_backend,
+ level_mfg,
+ level_model,
+ level_desc
+}
+level;
+
+typedef struct url_entry
+{
+ struct url_entry *next;
+ char *name;
+}
+url_entry;
+
+typedef struct model_entry
+{
+ struct model_entry *next;
+ char *name;
+ char *interface;
+ struct url_entry *url;
+ char *comment;
+ enum status_entry status;
+ char *usb_vendor_id;
+ char *usb_product_id;
+ SANE_Bool ignore_usb_id;
+ char *scsi_vendor_id;
+ char *scsi_product_id;
+ SANE_Bool scsi_is_processor;
+}
+model_entry;
+
+typedef struct desc_entry
+{
+ struct desc_entry *next;
+ char *desc;
+ struct url_entry *url;
+ char *comment;
+}
+desc_entry;
+
+typedef struct mfg_entry
+{
+ struct mfg_entry *next;
+ char *name;
+ struct url_entry *url;
+ char *comment;
+ struct model_entry *model;
+}
+mfg_entry;
+
+typedef struct type_entry
+{
+ struct type_entry *next;
+ enum device_type type;
+ struct desc_entry *desc;
+ struct mfg_entry *mfg;
+}
+type_entry;
+
+typedef struct backend_entry
+{
+ struct backend_entry *next;
+ char *name;
+ char *version;
+ char *manpage;
+ struct url_entry *url;
+ char *comment;
+ struct type_entry *type;
+ SANE_Bool new;
+}
+backend_entry;
+
+typedef struct model_record_entry
+{
+ struct model_record_entry *next;
+ char *name;
+ char *interface;
+ struct url_entry *url;
+ char *comment;
+ enum status_entry status;
+ char *usb_vendor_id;
+ char *usb_product_id;
+ char *scsi_vendor_id;
+ char *scsi_product_id;
+ SANE_Bool scsi_is_processor;
+ struct backend_entry *be;
+}
+model_record_entry;
+
+typedef struct mfg_record_entry
+{
+ struct mfg_record_entry *next;
+ char *name;
+ char *comment;
+ struct url_entry *url;
+ struct model_record_entry *model_record;
+}
+mfg_record_entry;
+
+typedef int statistics_type [status_complete + 1];
+
+
+typedef struct manufacturer_model_type
+{
+ struct manufacturer_model_type * next;
+ char *name;
+}
+manufacturer_model_type;
+
+typedef struct usbid_type
+{
+ struct usbid_type * next;
+ char *usb_vendor_id;
+ char *usb_product_id;
+ struct manufacturer_model_type *name;
+}
+usbid_type;
+
+typedef struct scsiid_type
+{
+ struct scsiid_type * next;
+ char *scsi_vendor_id;
+ char *scsi_product_id;
+ SANE_Bool is_processor;
+ struct manufacturer_model_type *name;
+}
+scsiid_type;
+
+static char *program_name;
+static int debug = 0;
+static int current_debug_level = 0;
+static char *search_dir_spec = 0;
+static backend_entry *first_backend = 0;
+static enum output_mode mode = output_mode_ascii;
+static char *title = 0;
+static char *intro = 0;
+static SANE_String desc_name = 0;
+static const char *status_name[] =
+ {"Unknown", "Unsupported", "Untested", "Minimal", "Basic",
+ "Good", "Complete"};
+static const char *device_type_name[] =
+ {"Unknown", "Scanners", "Still cameras", "Video Cameras", "Meta backends",
+ "APIs"};
+static const char *device_type_aname[] =
+ {"UKNOWN", "SCANNERS", "STILL", "VIDEO", "META",
+ "API"};
+static const char *status_color[] =
+ {COLOR_UNKNOWN, COLOR_UNSUPPORTED, COLOR_UNTESTED, COLOR_MINIMAL,
+ COLOR_BASIC, COLOR_GOOD, COLOR_COMPLETE};
+
+
+static void
+debug_call (const char *fmt, ...)
+{
+ va_list ap;
+ char *level_txt;
+
+ va_start (ap, fmt);
+ if (debug >= current_debug_level)
+ {
+ /* print to stderr */
+ switch (current_debug_level)
+ {
+ case 0:
+ level_txt = "ERROR:";
+ break;
+ case 1:
+ level_txt = "Warning:";
+ break;
+ case 2:
+ level_txt = "Info:";
+ break;
+ default:
+ level_txt = "";
+ break;
+ }
+ if (desc_name)
+ fprintf (stderr, "%s: %8s ", desc_name, level_txt);
+ else
+ fprintf (stderr, "[%s] %8s ", program_name, level_txt);
+ vfprintf (stderr, fmt, ap);
+ }
+ va_end (ap);
+}
+
+static void
+print_usage (char *program_name)
+{
+ printf ("Usage: %s [-s dir] [-m mode] [-d level] [-h] [-V]\n",
+ program_name);
+ printf (" -s|--search-dir dir "
+ "Specify the directory that contains .desc files \n"
+ " "
+ "(multiple directories can be concatenated by \":\")\n");
+ printf (" -m|--mode mode "
+ "Output mode (ascii, html-backends-split, html-mfgs,\n"
+ " xml, statistics, usermap, db, udev, udev+acl, udev+hwdb, hwdb, plist, hal, hal-new)\n");
+ printf (" -t|--title \"title\" The title used for HTML pages\n");
+ printf (" -i|--intro \"intro\" A short description of the "
+ "contents of the page\n");
+ printf (" -d|--debug-level level Specify debug level (0-3)\n");
+ printf (" -h|--help Print help message\n");
+ printf (" -V|--version Print version information\n");
+ printf ("Report bugs to <henning@meier-geinitz.de>\n");
+}
+
+static void
+print_version (void)
+{
+ printf ("sane-desc %s (%s)\n", SANE_DESC_VERSION, PACKAGE_STRING);
+ printf ("Copyright (C) 2002-2006 Henning Meier-Geinitz "
+ "<henning@meier-geinitz.de>\n"
+ "sane-desc comes with NO WARRANTY, to the extent permitted by "
+ "law.\n"
+ "You may redistribute copies of sane-desc under the terms of the "
+ "GNU General\n"
+ "Public License.\n"
+ "For more information about these matters, see the file named "
+ "COPYING.\n");
+}
+
+static SANE_Bool
+get_options (int argc, char **argv)
+{
+ int longindex;
+ int opt;
+ static struct option desc_options[] = {
+ {"search-dir", required_argument, NULL, 's'},
+ {"mode", required_argument, NULL, 'm'},
+ {"title", required_argument, NULL, 't'},
+ {"intro", required_argument, NULL, 'i'},
+ {"debug-level", required_argument, NULL, 'd'},
+ {"help", 0, NULL, 'h'},
+ {"version", 0, NULL, 'V'},
+ {0, 0, 0, 0}
+ };
+
+ while ((opt = getopt_long (argc, argv, "s:m:t:i:d:hV", desc_options,
+ &longindex)) != -1)
+ {
+ switch (opt)
+ {
+ case 'h':
+ print_usage (argv[0]);
+ exit (0);
+ case 'V':
+ print_version ();
+ exit (0);
+ case 's':
+ search_dir_spec = strdup (optarg);
+ DBG_INFO ("setting search directory to `%s'\n", search_dir_spec);
+ break;
+ case 'm':
+ if (strcmp (optarg, "ascii") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_ascii;
+ }
+ else if (strcmp (optarg, "xml") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_xml;
+ }
+ else if (strcmp (optarg, "html-backends-split") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_html_backends_split;
+ }
+ else if (strcmp (optarg, "html-mfgs") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_html_mfgs;
+ }
+ else if (strcmp (optarg, "statistics") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_statistics;
+ }
+ else if (strcmp (optarg, "usermap") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_usermap;
+ }
+ else if (strcmp (optarg, "db") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_db;
+ }
+ else if (strcmp (optarg, "udev") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_udev;
+ }
+ else if (strcmp (optarg, "udev+acl") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_udevacl;
+ }
+ else if (strcmp (optarg, "udev+hwdb") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_udevhwdb;
+ }
+ else if (strcmp (optarg, "hwdb") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_hwdb;
+ }
+ else if (strcmp (optarg, "plist") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_plist;
+ }
+ else if (strcmp (optarg, "hal") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_hal;
+ }
+ else if (strcmp (optarg, "hal-new") == 0)
+ {
+ DBG_INFO ("Output mode: %s\n", optarg);
+ mode = output_mode_halnew;
+ }
+ else
+ {
+ DBG_ERR ("Unknown output mode: %s\n", optarg);
+ exit (1);
+ }
+ break;
+ case 't':
+ title = optarg;
+ DBG_INFO ("setting title to `%s'\n", optarg);
+ break;
+ case 'i':
+ intro = optarg;
+ DBG_INFO ("setting intro to `%s'\n", optarg);
+ break;
+ case 'd':
+ debug = atoi (optarg);
+ DBG_INFO ("setting debug level to %d\n", debug);
+ break;
+ case '?':
+ DBG_ERR ("unknown option (use -h for help)\n");
+ return SANE_FALSE;
+ case ':':
+ DBG_ERR ("missing parameter (use -h for help)\n");
+ return SANE_FALSE;
+ default:
+ DBG_ERR ("missing option (use -h for help)\n");
+ return SANE_FALSE;
+ }
+ }
+ if (!search_dir_spec)
+ search_dir_spec = ".";
+ return SANE_TRUE;
+}
+
+static int
+char_compare (char char1, char char2)
+{
+ char1 = toupper (char1);
+ char2 = toupper (char2);
+
+ if (char1 < char2)
+ return -1;
+ else if (char1 > char2)
+ return 1;
+ else
+ return 0;
+}
+
+static int
+num_compare (char *num_string1, char *num_string2)
+{
+ int num1 = atoi (num_string1);
+ int num2 = atoi (num_string2);
+ if (num1 < num2)
+ return -1;
+ else if (num1 > num2)
+ return 1;
+ else
+ return 0;
+}
+
+/* Compare two strings, try to sort numbers correctly (600 < 1200) */
+static int
+string_compare (char *string1, char *string2)
+{
+ int count = 0;
+ int compare = 0;
+
+ if (!string1)
+ {
+ if (!string2)
+ return 0;
+ else
+ return 1;
+ }
+ else if (!string2)
+ return -1;
+
+ while (string1[count] && string2[count])
+ {
+ if (isdigit (string1[count]) && isdigit (string2[count]))
+ compare = num_compare (&string1[count], &string2[count]);
+ else
+ compare = char_compare (string1[count], string2[count]);
+ if (compare != 0)
+ return compare;
+ count++;
+ }
+ return char_compare (string1[count], string2[count]);
+}
+
+/* Add URLs to the end of the list if they are unique */
+static url_entry *
+update_url_list (url_entry * first_url, char *new_url)
+{
+ url_entry *url = first_url;
+ SANE_Bool found = SANE_FALSE;
+
+ while (url && url->name)
+ {
+ if (string_compare (url->name, new_url) == 0)
+ found = SANE_TRUE;
+ url = url->next;
+ }
+ if (found)
+ return first_url;
+
+ url = first_url;
+ if (url)
+ {
+ while (url->next)
+ url = url->next;
+ url->next = calloc (1, sizeof (url_entry));
+ url = url->next;
+ }
+ else
+ {
+ first_url = calloc (1, sizeof (url_entry));
+ url = first_url;
+ }
+ if (!url)
+ {
+ DBG_ERR ("update_url_list: couldn't calloc url_entry\n");
+ exit (1);
+ }
+ url->name = new_url;
+ return first_url;
+}
+
+/* Get the next token, ignoring escaped quotation marks */
+static const char *
+get_token (const char *str, char **string_const)
+{
+ const char *start;
+ size_t len;
+
+ str = sanei_config_skip_whitespace (str);
+
+ if (*str == '"')
+ {
+ start = ++str;
+ while (*str && (*str != '"' || *(str - 1) == '\\'))
+ ++str;
+ len = str - start;
+ if (*str == '"')
+ ++str;
+ else
+ start = 0; /* final double quote is missing */
+ }
+ else
+ {
+ start = str;
+ while (*str && !isspace (*str))
+ ++str;
+ len = str - start;
+ }
+ if (start)
+ *string_const = strndup (start, len);
+ else
+ *string_const = NULL;
+ return str;
+}
+
+/* Checks a line for a keyword token and determines keyword/string argument */
+static SANE_Status
+read_keyword (SANE_String line, SANE_String keyword_token,
+ parameter_type p_type, void *argument)
+{
+ SANE_String_Const cp;
+ SANE_Char *word;
+
+ word = 0;
+
+ cp = get_token (line, &word);
+
+ if (!word)
+ {
+ DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
+ return SANE_STATUS_INVAL;
+ }
+
+ if (strcmp (word, keyword_token) != 0)
+ {
+ free(word);
+ return SANE_STATUS_INVAL;
+ }
+
+ free (word);
+ word = 0;
+
+ switch (p_type)
+ {
+ case param_none:
+ return SANE_STATUS_GOOD;
+ case param_string:
+ {
+ char *pos;
+ cp = get_token (cp, &word);
+ if (!word)
+ {
+ DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
+ return SANE_STATUS_INVAL;
+ }
+ /* remove escaped quotations */
+ while ((pos = strstr (word, "\\\"")) != 0)
+ *pos = ' ';
+
+ DBG_DBG ("read_keyword: set entry `%s' to `%s'\n", keyword_token,
+ word);
+ *(SANE_String *) argument = strdup (word);
+ break;
+ }
+ case param_two_strings:
+ {
+ char *pos;
+ char **strings = malloc (2 * sizeof (SANE_String));
+
+ cp = get_token (cp, &word);
+ if (!word)
+ {
+ free(strings);
+ DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
+ return SANE_STATUS_INVAL;
+ }
+ /* remove escaped quotations */
+ while ((pos = strstr (word, "\\\"")) != 0)
+ *pos = ' ';
+ DBG_INFO ("read_keyword: set first entry of `%s' to `%s'\n", keyword_token,
+ word);
+ strings[0] = strdup (word);
+ if (word)
+ free (word);
+
+ cp = get_token (cp, &word);
+ if (!word)
+ {
+ free(strings);
+ DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
+ return SANE_STATUS_INVAL;
+ }
+ /* remove escaped quotations */
+ while ((pos = strstr (word, "\\\"")) != 0)
+ *pos = ' ';
+ DBG_INFO ("read_keyword: set second entry of `%s' to `%s'\n", keyword_token,
+ word);
+ strings[1] = strdup (word);
+ * (SANE_String **) argument = strings;
+ break;
+ }
+ case param_three_strings:
+ {
+ char *pos;
+ char **strings = malloc (3 * sizeof (SANE_String));
+
+ cp = get_token (cp, &word);
+ if (!word)
+ {
+ free(strings);
+ DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
+ return SANE_STATUS_INVAL;
+ }
+ /* remove escaped quotations */
+ while ((pos = strstr (word, "\\\"")) != 0)
+ *pos = ' ';
+ DBG_INFO ("read_keyword: set first entry of `%s' to `%s'\n", keyword_token,
+ word);
+ strings[0] = strdup (word);
+ if (word)
+ free (word);
+
+ cp = get_token (cp, &word);
+ if (!word)
+ {
+ free(strings);
+ DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
+ return SANE_STATUS_INVAL;
+ }
+ /* remove escaped quotations */
+ while ((pos = strstr (word, "\\\"")) != 0)
+ *pos = ' ';
+ DBG_INFO ("read_keyword: set second entry of `%s' to `%s'\n", keyword_token,
+ word);
+ strings[1] = strdup (word);
+ if (word)
+ free (word);
+
+ cp = get_token (cp, &word);
+ if (!word)
+ {
+ free(strings);
+ DBG_ERR ("read_keyword: missing quotation mark: %s\n", line);
+ return SANE_STATUS_INVAL;
+ }
+ /* remove escaped quotations */
+ while ((pos = strstr (word, "\\\"")) != 0)
+ *pos = ' ';
+ DBG_INFO ("read_keyword: set third entry of `%s' to `%s'\n", keyword_token,
+ word);
+ strings[2] = strdup (word);
+ * (SANE_String **) argument = strings;
+ break;
+ }
+ default:
+ DBG_ERR ("read_keyword: unknown param_type %d\n", p_type);
+ return SANE_STATUS_INVAL;
+ }
+
+ if (word)
+ free (word);
+ word = 0;
+ return SANE_STATUS_GOOD;
+}
+
+/* Check for a all-lowercase 4-digit hex number (e.g. 0x1234) */
+static SANE_Bool
+check_hex (SANE_String string)
+{
+ unsigned int i;
+
+ if (strlen (string) != 6)
+ return SANE_FALSE;
+ if (strncmp (string, "0x", 2) != 0)
+ return SANE_FALSE;
+ for (i = 0; i < strlen (string); i++)
+ {
+ if (isupper (string[i]))
+ return SANE_FALSE;
+ }
+ for (i = 2; i < strlen (string); i++)
+ {
+ if (!isxdigit (string[i]))
+ return SANE_FALSE;
+ }
+ return SANE_TRUE;
+}
+
+/* Read and interprete the .desc files */
+static SANE_Bool
+read_files (void)
+{
+ struct stat stat_buf;
+ DIR *dir;
+ struct dirent *dir_entry;
+ FILE *fp;
+ char file_name[PATH_MAX];
+ SANE_Char line[4096], *word;
+ SANE_String_Const cp;
+ backend_entry *current_backend = 0;
+ type_entry *current_type = 0;
+ mfg_entry *current_mfg = 0;
+ model_entry *current_model = 0;
+ enum level current_level = level_backend;
+ char *search_dir = search_dir_spec, *end = 0;
+
+ DBG_INFO ("looking for .desc files in `%s'\n", search_dir_spec);
+
+ while (search_dir && search_dir[0])
+ {
+ end = strchr (search_dir, ':');
+ if (end)
+ end[0] = '\0';
+ DBG_INFO ("reading directory `%s'\n", search_dir);
+
+ if (stat (search_dir, &stat_buf) < 0)
+ {
+ DBG_ERR ("cannot stat `%s' (%s)\n", search_dir, strerror (errno));
+ return SANE_FALSE;
+ }
+ if (!S_ISDIR (stat_buf.st_mode))
+ {
+ DBG_ERR ("`%s' is not a directory\n", search_dir);
+ return SANE_FALSE;
+ }
+ if ((dir = opendir (search_dir)) == 0)
+ {
+ DBG_ERR ("cannot read directory `%s' (%s)\n", search_dir,
+ strerror (errno));
+ return SANE_FALSE;
+ }
+
+ while ((dir_entry = readdir (dir)) != NULL)
+ {
+ if (strlen (dir_entry->d_name) > 5 &&
+ strcmp (dir_entry->d_name + strlen (dir_entry->d_name) - 5,
+ ".desc") == 0)
+ {
+ if (strlen (search_dir)
+ + strlen (dir_entry->d_name) + 1 + 1 > PATH_MAX)
+ {
+ DBG_ERR ("filename too long\n");
+ return SANE_FALSE;
+ }
+ sprintf (file_name, "%s/%s", search_dir, dir_entry->d_name);
+ DBG_INFO ("-> reading desc file: %s\n", file_name);
+ fp = fopen (file_name, "r");
+ if (!fp)
+ {
+ DBG_ERR ("can't open desc file: %s (%s)\n", file_name,
+ strerror (errno));
+ return SANE_FALSE;
+ }
+ /* now we check if everything is ok with the previous backend
+ before we read the new one */
+ if (current_backend)
+ {
+ type_entry *current_type = current_backend->type;
+ int no_usbids = 0;
+ int no_interface = 0;
+ int no_status = 0;
+
+ while (current_type)
+ {
+ if (current_type->type == type_scanner ||
+ current_type->type == type_stillcam ||
+ current_type->type == type_vidcam)
+ {
+ mfg_entry *current_mfg = current_type->mfg;
+
+ while (current_mfg)
+ {
+ model_entry *current_model = current_mfg->model;
+
+ while (current_model)
+ {
+ if (current_model->status == status_unknown)
+ {
+ DBG_INFO
+ ("Backend `%s': `%s' `%s' does not have a status\n",
+ current_backend->name,
+ current_mfg->name,
+ current_model->name);
+ no_status++;
+ }
+ if (!current_model->interface)
+ {
+ DBG_INFO
+ ("Backend `%s': `%s' `%s' does not have an interface\n",
+ current_backend->name,
+ current_mfg->name,
+ current_model->name);
+ no_interface++;
+ }
+ else if (strstr (current_model->interface, "USB"))
+ {
+ if ((!current_model->usb_vendor_id || !current_model->usb_product_id)
+ && !current_model->ignore_usb_id)
+ {
+ DBG_INFO ("`%s' seems to provide a USB device "
+ "without :usbid (%s %s)\n",
+ current_backend->name,
+ current_mfg->name,
+ current_model->name);
+ no_usbids++;
+ }
+ }
+ current_model = current_model->next;
+ }
+ current_mfg = current_mfg->next;
+ }
+ }
+ current_type = current_type->next;
+ }
+ if (no_status)
+ {
+ DBG_WARN ("Backend `%s': %d devices without :status\n",
+ current_backend->name, no_status);
+ }
+ if (no_interface)
+ {
+ DBG_WARN ("Backend `%s': %d devices without :interface\n",
+ current_backend->name, no_interface);
+ }
+ if (no_usbids)
+ {
+ DBG_WARN ("Backend `%s': %d USB devices without :usbid\n",
+ current_backend->name, no_usbids);
+ }
+ }
+ desc_name = dir_entry->d_name;
+ current_backend = 0;
+ current_type = 0;
+ current_mfg = 0;
+ current_model = 0;
+ while (sanei_config_read (line, sizeof (line), fp))
+ {
+ char *string_entry = 0;
+ char **two_string_entry;
+ char **three_string_entry;
+ word = 0;
+
+ cp = get_token (line, &word);
+ if (!word || cp == line)
+ {
+ DBG_DBG ("ignoring empty line\n");
+ if (word)
+ free (word);
+ word = 0;
+ continue;
+ }
+ if (word[0] == ';')
+ {
+ DBG_DBG ("ignoring comment line\n");
+ free (word);
+ word = 0;
+ continue;
+ }
+ DBG_DBG ("line: %s\n", line);
+
+ if (read_keyword
+ (line, ":backend", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ backend_entry *be = first_backend, *prev_be =
+ 0, *new_be = 0;
+ DBG_INFO ("creating backend entry `%s'\n",
+ string_entry);
+
+ new_be = calloc (1, sizeof (backend_entry));
+ if (!new_be)
+ {
+ DBG_ERR ("calloc failed (%s)\n", strerror (errno));
+ return SANE_FALSE;
+ }
+ new_be->name = string_entry;
+ new_be->new = SANE_FALSE;
+
+ if (!be)
+ {
+ first_backend = new_be;
+ be = new_be;
+ }
+ else
+ {
+ while (be)
+ {
+ int compare =
+ string_compare (new_be->name, be->name);
+ if (compare <= 0)
+ {
+ backend_entry *be_tmp = be;
+ be = new_be;
+ be->next = be_tmp;
+ if (!prev_be)
+ first_backend = be;
+ else
+ prev_be->next = be;
+ break;
+ }
+ prev_be = be;
+ be = be->next;
+ }
+ if (!be) /* last entry */
+ {
+ prev_be->next = new_be;
+ be = prev_be->next;
+ }
+ }
+ current_backend = be;
+ current_type = 0;
+ current_mfg = 0;
+ current_model = 0;
+ current_level = level_backend;
+ continue;
+ }
+ if (!current_backend)
+ {
+ DBG_ERR ("use `:backend' keyword first\n");
+ return SANE_FALSE;
+ }
+ if (read_keyword
+ (line, ":version", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ if (current_backend->version)
+ {
+ DBG_WARN
+ ("overwriting version of backend `%s' to `%s'"
+ "(was: `%s')\n", current_backend->name,
+ string_entry, current_backend->version,
+ current_backend->version);
+ }
+
+ DBG_INFO ("setting version of backend `%s' to `%s'\n",
+ current_backend->name, string_entry);
+ current_backend->version = string_entry;
+ continue;
+ }
+ if (read_keyword
+ (line, ":status", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ switch (current_level)
+ {
+ case level_model:
+ if (current_model->status != status_unknown)
+ {
+ DBG_WARN
+ ("overwriting status of model `%s' (backend `%s')\n",
+ current_model->name, current_backend->name);
+ }
+ if (strcmp (string_entry, ":minimal") == 0)
+ {
+ DBG_INFO
+ ("setting status of model `%s' to `minimal'\n",
+ current_model->name);
+ current_model->status = status_minimal;
+ }
+ else if (strcmp (string_entry, ":basic") == 0)
+ {
+ DBG_INFO
+ ("setting status of model `%s' to `basic'\n",
+ current_model->name);
+ current_model->status = status_basic;
+ }
+ else if (strcmp (string_entry, ":good") == 0)
+ {
+ DBG_INFO
+ ("setting status of model `%s' to `good'\n",
+ current_model->name);
+ current_model->status = status_good;
+ }
+ else if (strcmp (string_entry, ":complete") == 0)
+ {
+ DBG_INFO
+ ("setting status of model `%s' to `complete'\n",
+ current_model->name);
+ current_model->status = status_complete;
+ }
+ else if (strcmp (string_entry, ":untested") == 0)
+ {
+ DBG_INFO
+ ("setting status of model `%s' to `untested'\n",
+ current_model->name);
+ current_model->status = status_untested;
+ }
+ else if (strcmp (string_entry, ":unsupported") == 0)
+ {
+ DBG_INFO
+ ("setting status of model `%s' to `unsupported'\n",
+ current_model->name);
+ current_model->status = status_unsupported;
+ }
+ else
+ {
+ DBG_ERR
+ ("unknown status of model `%s': `%s' (backend `%s')\n",
+ current_model->name, string_entry,
+ current_backend->name);
+ current_model->status = status_untested;
+ return SANE_FALSE;
+ }
+ break;
+ default:
+ DBG_ERR
+ ("level %d not implemented for :status (backend `%s')\n",
+ current_level, current_backend->name);
+ return SANE_FALSE;
+ }
+
+
+ continue;
+ }
+ if (read_keyword (line, ":new", param_string, &string_entry)
+ == SANE_STATUS_GOOD)
+ {
+ if (strcmp (string_entry, ":yes") == 0)
+ {
+ DBG_INFO
+ ("backend %s is new in this SANE release\n",
+ current_backend->name);
+ current_backend->new = SANE_TRUE;
+ }
+ else if (strcmp (string_entry, ":no") == 0)
+ {
+ DBG_INFO
+ ("backend %s is NOT new in this SANE release\n",
+ current_backend->name);
+ current_backend->new = SANE_FALSE;
+ }
+ else
+ {
+ DBG_ERR ("unknown :new parameter of backend `%s': "
+ "`%s'\n", current_backend->name,
+ string_entry);
+ current_backend->new = SANE_FALSE;
+ return SANE_FALSE;
+ }
+ continue;
+ }
+ if (read_keyword
+ (line, ":manpage", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ if (current_backend->manpage)
+ {
+ DBG_WARN
+ ("overwriting manpage of backend `%s' to `%s'"
+ "(was: `%s')\n", current_backend->name,
+ string_entry, current_backend->manpage);
+ }
+
+ DBG_INFO ("setting manpage of backend `%s' to `%s'\n",
+ current_backend->name, string_entry);
+ current_backend->manpage = string_entry;
+ continue;
+ }
+ if (read_keyword
+ (line, ":devicetype", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ type_entry *type = 0;
+
+ type = current_backend->type;
+
+ DBG_INFO
+ ("adding `%s' to list of device types of backend "
+ "`%s'\n", string_entry, current_backend->name);
+
+ if (type)
+ {
+ while (type->next)
+ type = type->next;
+ type->next = calloc (1, sizeof (type_entry));
+ type = type->next;
+ }
+ else
+ {
+ current_backend->type =
+ calloc (1, sizeof (type_entry));
+ type = current_backend->type;
+ }
+
+ type->type = type_unknown;
+ if (strcmp (string_entry, ":scanner") == 0)
+ {
+ DBG_INFO ("setting device type of backend `%s' to "
+ "scanner\n", current_backend->name);
+ type->type = type_scanner;
+ }
+ else if (strcmp (string_entry, ":stillcam") == 0)
+ {
+ DBG_INFO ("setting device type of backend `%s' to "
+ "still camera\n", current_backend->name);
+ type->type = type_stillcam;
+ }
+ else if (strcmp (string_entry, ":vidcam") == 0)
+ {
+ DBG_INFO ("setting device type of backend `%s' to "
+ "video camera\n", current_backend->name);
+ type->type = type_vidcam;
+ }
+ else if (strcmp (string_entry, ":api") == 0)
+ {
+ DBG_INFO ("setting device type of backend `%s' to "
+ "API\n", current_backend->name);
+ type->type = type_api;
+ }
+ else if (strcmp (string_entry, ":meta") == 0)
+ {
+ DBG_INFO ("setting device type of backend `%s' to "
+ "meta\n", current_backend->name);
+ type->type = type_meta;
+ }
+ else
+ {
+ DBG_ERR
+ ("unknown device type of backend `%s': `%s'\n",
+ current_backend->name, string_entry);
+ type->type = type_unknown;
+ return SANE_FALSE;
+ }
+ current_type = type;
+ current_mfg = 0;
+ current_model = 0;
+ continue;
+ }
+ if (read_keyword
+ (line, ":desc", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ if (!current_type)
+ {
+ DBG_ERR
+ ("use `:devicetype' keyword first (backend `%s')\n",
+ current_backend->name);
+ return SANE_FALSE;
+ }
+ if (current_type->type < type_meta)
+ {
+ DBG_ERR
+ ("use `:desc' for `:api' and `:meta' only (backend `%s')\n",
+ current_backend->name);
+ return SANE_FALSE;
+ }
+
+ if (current_type->desc)
+ {
+ DBG_WARN
+ ("overwriting description of device type of "
+ "backend `%s' to `%s' (was: `%s')\n",
+ current_backend->name, string_entry,
+ current_type->desc);
+ }
+
+ DBG_INFO
+ ("setting description of backend `%s' to `%s'\n",
+ current_backend->name, string_entry);
+ current_type->desc = calloc (1, sizeof (desc_entry));
+ if (!current_type->desc)
+ {
+ DBG_ERR ("calloc failed (%s)\n", strerror (errno));
+ return SANE_FALSE;
+ }
+ current_type->desc->desc = string_entry;
+ current_level = level_desc;
+ current_mfg = 0;
+ current_model = 0;
+ continue;
+ }
+ if (read_keyword (line, ":mfg", param_string, &string_entry)
+ == SANE_STATUS_GOOD)
+ {
+ mfg_entry *mfg = 0;
+
+ if (!current_type)
+ {
+ DBG_ERR
+ ("use `:devicetype' keyword first (backend `%s')\n",
+ current_backend->name);
+ return SANE_FALSE;
+ }
+ if (current_type->type >= type_meta)
+ {
+ DBG_ERR
+ ("use `:mfg' for hardware devices only (backend `%s')\n",
+ current_backend->name);
+ return SANE_FALSE;
+ }
+
+ mfg = current_type->mfg;
+ if (mfg)
+ {
+ while (mfg->next)
+ mfg = mfg->next;
+ mfg->next = calloc (1, sizeof (mfg_entry));
+ mfg = mfg->next;
+ }
+ else
+ {
+ current_type->mfg = calloc (1, sizeof (mfg_entry));
+ mfg = current_type->mfg;
+ }
+
+ if (!mfg)
+ {
+ DBG_ERR ("calloc failed (%s)\n", strerror (errno));
+ return SANE_FALSE;
+ }
+ mfg->name = string_entry;
+ DBG_INFO ("adding mfg entry %s to backend `%s'\n",
+ string_entry, current_backend->name);
+ current_mfg = mfg;
+ current_model = 0;
+ current_level = level_mfg;
+ continue;
+ }
+ if (read_keyword
+ (line, ":model", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ model_entry *model = 0;
+
+ if (!current_type)
+ {
+ DBG_ERR
+ ("use `:devicetype' keyword first (backend `%s')\n",
+ current_backend->name);
+ return SANE_FALSE;
+ }
+ if (current_level != level_mfg
+ && current_level != level_model)
+ {
+ DBG_ERR
+ ("use `:mfg' keyword first (backend `%s')\n",
+ current_backend->name);
+ return SANE_FALSE;
+ }
+ model = current_mfg->model;
+ if (model)
+ {
+ while (model->next)
+ model = model->next;
+ model->next = calloc (1, sizeof (model_entry));
+ model = model->next;
+ }
+ else
+ {
+ current_mfg->model =
+ calloc (1, sizeof (model_entry));
+ model = current_mfg->model;
+ }
+
+ if (!model)
+ {
+ DBG_ERR ("calloc failed (%s)\n", strerror (errno));
+ return SANE_FALSE;
+ }
+ model->name = string_entry;
+ model->status = status_unknown;
+ DBG_INFO
+ ("adding model entry %s to manufacturer `%s'\n",
+ string_entry, current_mfg->name);
+ current_model = model;
+ current_level = level_model;
+ continue;
+ }
+ if (read_keyword
+ (line, ":interface", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ if (!current_model)
+ {
+ DBG_WARN
+ ("ignored `%s' :interface, only allowed for "
+ "hardware devices\n", current_backend->name);
+ continue;
+ }
+
+ if (current_model->interface)
+ {
+ DBG_WARN ("overwriting `%s's interface of model "
+ "`%s' to `%s' (was: `%s')\n",
+ current_backend->name,
+ current_model->name, string_entry,
+ current_model->interface);
+ }
+
+ DBG_INFO ("setting interface of model `%s' to `%s'\n",
+ current_model->name, string_entry);
+ current_model->interface = string_entry;
+ continue;
+ }
+ if (read_keyword
+ (line, ":scsi", param_three_strings,
+ &three_string_entry) == SANE_STATUS_GOOD)
+ {
+ if (!current_model)
+ {
+ DBG_WARN
+ ("ignored `%s' :scsi, only allowed for "
+ "hardware devices\n", current_backend->name);
+ continue;
+ }
+
+ DBG_INFO ("setting scsi vendor and product ids of model `%s' to `%s/%s'\n",
+ current_model->name, three_string_entry[0], three_string_entry[1]);
+ if (strcasecmp (three_string_entry[0], "ignore") == 0)
+ {
+ DBG_INFO ("Ignoring `%s's scsi-entries of `%s'\n",
+ current_backend->name,
+ current_model->name);
+ continue;
+ }
+ if (strcasecmp (three_string_entry[2], "processor") == 0){
+ current_model->scsi_is_processor = SANE_TRUE;
+ current_model->scsi_vendor_id = three_string_entry[0];
+ current_model->scsi_product_id = three_string_entry[1];
+ }
+ else
+ {
+ DBG_INFO ("scsi-format info in %s is invalid -> break\n", current_backend->name);
+ continue;
+ }
+ continue;
+ }
+ if (read_keyword
+ (line, ":usbid", param_two_strings,
+ &two_string_entry) == SANE_STATUS_GOOD)
+ {
+ if (!current_model)
+ {
+ DBG_WARN
+ ("ignored `%s' :usbid, only allowed for "
+ "hardware devices\n", current_backend->name);
+ continue;
+ }
+ if (strcasecmp (two_string_entry[0], "ignore") == 0)
+ {
+ DBG_INFO ("Ignoring `%s's USB ids of `%s'\n",
+ current_backend->name,
+ current_model->name);
+ current_model->ignore_usb_id = SANE_TRUE;
+ continue;
+ }
+ if (!check_hex (two_string_entry[0]))
+ {
+ DBG_WARN ("`%s's USB vendor id of `%s' is "
+ "not a lowercase 4-digit hex number: "
+ "`%s'\n", current_backend->name,
+ current_model->name, two_string_entry[0]);
+ continue;
+ }
+ if (!check_hex (two_string_entry[1]))
+ {
+ DBG_WARN ("`%s's USB product id of `%s' is "
+ "not a lowercase 4-digit hex number: "
+ "`%s'\n", current_backend->name,
+ current_model->name, two_string_entry[1]);
+ continue;
+ }
+
+ if (current_model->usb_vendor_id || current_model->usb_product_id)
+ {
+ DBG_WARN ("overwriting `%s's USB ids of model "
+ "`%s' to `%s/%s' (was: `%s/%s')\n",
+ current_backend->name,
+ current_model->name, two_string_entry[0],
+ two_string_entry[1],
+ current_model->usb_vendor_id,
+ current_model->usb_product_id);
+ }
+
+ DBG_INFO ("setting USB vendor and product ids of model `%s' to `%s/%s'\n",
+ current_model->name, two_string_entry[0], two_string_entry[1]);
+ current_model->usb_vendor_id = two_string_entry[0];
+ current_model->usb_product_id = two_string_entry[1];
+ continue;
+ }
+ if (read_keyword (line, ":url", param_string, &string_entry)
+ == SANE_STATUS_GOOD)
+ {
+ switch (current_level)
+ {
+ case level_backend:
+ current_backend->url =
+ update_url_list (current_backend->url,
+ string_entry);
+ DBG_INFO ("adding `%s' to list of urls of backend "
+ "`%s'\n", string_entry,
+ current_backend->name);
+ break;
+ case level_mfg:
+ current_mfg->url =
+ update_url_list (current_mfg->url, string_entry);
+ DBG_INFO ("adding `%s' to list of urls of mfg "
+ "`%s'\n", string_entry,
+ current_mfg->name);
+ break;
+ case level_desc:
+ current_type->desc->url =
+ update_url_list (current_type->desc->url,
+ string_entry);
+ DBG_INFO
+ ("adding `%s' to list of urls of description "
+ "for backend `%s'\n", string_entry,
+ current_backend->name);
+ break;
+ case level_model:
+ current_model->url =
+ update_url_list (current_model->url,
+ string_entry);
+ DBG_INFO ("adding `%s' to list of urls of model "
+ "`%s'\n", string_entry,
+ current_model->name);
+ break;
+ default:
+ DBG_ERR
+ ("level %d not implemented for :url (backend `%s')\n",
+ current_level, current_backend->name);
+ return SANE_FALSE;
+ }
+ continue;
+ }
+ if (read_keyword
+ (line, ":comment", param_string,
+ &string_entry) == SANE_STATUS_GOOD)
+ {
+ switch (current_level)
+ {
+ case level_backend:
+ current_backend->comment = string_entry;
+ DBG_INFO ("setting comment of backend %s to `%s'\n",
+ current_backend->name, string_entry);
+ break;
+ case level_mfg:
+ current_mfg->comment = string_entry;
+ DBG_INFO
+ ("setting comment of manufacturer %s to `%s'\n",
+ current_mfg->name, string_entry);
+ break;
+ case level_desc:
+ current_type->desc->comment = string_entry;
+ DBG_INFO ("setting comment of description for "
+ "backend %s to `%s'\n",
+ current_backend->name, string_entry);
+ break;
+ case level_model:
+ current_model->comment = string_entry;
+ DBG_INFO ("setting comment of model %s to `%s'\n",
+ current_model->name, string_entry);
+ break;
+ default:
+ DBG_ERR
+ ("level %d not implemented for `:comment' (backend `%s')\n",
+ current_level, current_backend->name);
+ return SANE_FALSE;
+ }
+ continue;
+ }
+ DBG_ERR
+ ("unknown keyword token in line `%s' of file `%s'\n",
+ line, file_name);
+ return SANE_FALSE;
+ } /* while (sanei_config_readline) */
+ fclose (fp);
+ } /* if (strlen) */
+ } /* while (direntry) */
+ if (closedir(dir) != 0)
+ {
+ DBG_ERR ("cannot close directory `%s' (%s)\n", search_dir,
+ strerror (errno));
+ return SANE_FALSE;
+ }
+ if (end)
+ search_dir = end + 1;
+ else
+ search_dir = (search_dir + strlen (search_dir));
+ }
+
+ desc_name = 0;
+ if (!first_backend)
+ {
+ DBG_ERR ("Couldn't find any .desc file\n");
+ return SANE_FALSE;
+ }
+ return SANE_TRUE;
+}
+
+/* Create a model_record_entry based on a model_entry */
+static model_record_entry *
+create_model_record (model_entry * model)
+{
+ model_record_entry *model_record;
+
+ model_record = calloc (1, sizeof (model_record_entry));
+ if (!model_record)
+ {
+ DBG_ERR ("create_model_record: couldn't calloc model_record_entry\n");
+ exit (1);
+ }
+ model_record->name = model->name;
+ model_record->status = model->status;
+ model_record->interface = model->interface;
+ model_record->url = model->url;
+ model_record->comment = model->comment;
+ model_record->usb_vendor_id = model->usb_vendor_id;
+ model_record->usb_product_id = model->usb_product_id;
+ model_record->scsi_vendor_id = model->scsi_vendor_id;
+ model_record->scsi_product_id = model->scsi_product_id;
+ model_record->scsi_is_processor = model->scsi_is_processor;
+ return model_record;
+}
+
+/* Calculate the priority of statuses: */
+/* minimal, basic, good, complete -> 2, untested -> 1, unsupported -> 0 */
+static int
+calc_priority (status_entry status)
+{
+ switch (status)
+ {
+ case status_untested:
+ return 1;
+ case status_unsupported:
+ return 0;
+ default:
+ return 2;
+ }
+}
+
+/* Insert model into list at the alphabetically correct position */
+static model_record_entry *
+update_model_record_list (model_record_entry * first_model_record,
+ model_entry * model, backend_entry * be)
+{
+ model_record_entry *model_record = first_model_record;
+
+ if (!first_model_record)
+ {
+ /* First model for this manufacturer */
+ first_model_record = create_model_record (model);
+ model_record = first_model_record;
+ }
+ else
+ {
+ model_record_entry *prev_model_record = 0;
+
+ while (model_record)
+ {
+ int compare = string_compare (model->name, model_record->name);
+ if (compare <= 0)
+ {
+ model_record_entry *tmp_model_record = model_record;
+ if ((compare == 0) &&
+ (string_compare (model->interface, model_record->interface) == 0) &&
+ (string_compare (model->usb_vendor_id, model_record->usb_vendor_id) == 0) &&
+ (string_compare (model->usb_product_id, model_record->usb_product_id) == 0))
+ {
+ /* Two entries for the same model */
+ int new_priority = calc_priority (model->status);
+ int old_priority = calc_priority (model_record->status);
+ if (new_priority < old_priority)
+ {
+ DBG_DBG
+ ("update_model_record_list: model %s ignored, backend %s has "
+ "higher priority\n", model->name,
+ model_record->be->name);
+ return first_model_record;
+ }
+ if (new_priority > old_priority)
+ {
+ DBG_DBG
+ ("update_model_record_list: model %s overrides the one from backend %s\n",
+ model->name, model_record->be->name);
+ tmp_model_record = model_record->next;
+ }
+ }
+ /* correct position */
+ model_record = create_model_record (model);
+ model_record->next = tmp_model_record;
+ if (!prev_model_record)
+ first_model_record = model_record;
+ else
+ prev_model_record->next = model_record;
+ break;
+ }
+ prev_model_record = model_record;
+ model_record = model_record->next;
+ }
+ if (!model_record) /* last entry */
+ {
+ prev_model_record->next = create_model_record (model);
+ model_record = prev_model_record->next;
+ }
+ } /* if (first_model_record) */
+ model_record->be = be;
+ DBG_DBG ("update_model_record_list: added model %s\n", model->name);
+ return first_model_record;
+}
+
+
+/* Insert manufacturer into list at the alphabetically correct position, */
+/* create new record if neccessary */
+static mfg_record_entry *
+update_mfg_record_list (mfg_record_entry * first_mfg_record, mfg_entry * mfg,
+ backend_entry * be)
+{
+ model_entry *model = mfg->model;
+ mfg_record_entry *mfg_record = first_mfg_record;
+
+ while (mfg_record)
+ {
+ if (string_compare (mfg_record->name, mfg->name) == 0)
+ {
+ /* Manufacturer already exists */
+ url_entry *mfg_url = mfg->url;
+
+ /* Manufacturer comments and (additional) URLs? */
+ if (!mfg_record->comment)
+ mfg_record->comment = mfg->comment;
+ while (mfg_url && mfg_url->name)
+ {
+ mfg_record->url = update_url_list (mfg_record->url,
+ mfg_url->name);
+ mfg_url = mfg_url->next;
+ }
+ break;
+ }
+ mfg_record = mfg_record->next;
+ }
+
+ if (!mfg_record)
+ {
+ /* Manufacturer doesn't exist yet */
+ url_entry *url = mfg->url;
+
+ mfg_record = calloc (1, sizeof (mfg_record_entry));
+ if (!mfg_record)
+ {
+ DBG_ERR ("update_mfg_record_list: couldn't calloc "
+ "mfg_record_entry\n");
+ exit (1);
+ }
+ mfg_record->name = mfg->name;
+ mfg_record->comment = mfg->comment;
+ while (url)
+ {
+ mfg_record->url = update_url_list (mfg_record->url, url->name);
+ url = url->next;
+ }
+ if (first_mfg_record != 0)
+ {
+ /* We already have one manufacturer in the list */
+ mfg_record_entry *new_mfg_record = mfg_record;
+ mfg_record_entry *prev_mfg_record = 0;
+
+ mfg_record = first_mfg_record;
+
+ while (mfg_record)
+ {
+ int compare =
+ string_compare (new_mfg_record->name, mfg_record->name);
+ if (compare <= 0)
+ {
+ mfg_record_entry *tmp_mfg_record = mfg_record;
+ mfg_record = new_mfg_record;
+ mfg_record->next = tmp_mfg_record;
+ if (!prev_mfg_record)
+ first_mfg_record = mfg_record;
+ else
+ prev_mfg_record->next = mfg_record;
+ break;
+ }
+ prev_mfg_record = mfg_record;
+ mfg_record = mfg_record->next;
+ }
+ if (!mfg_record) /* last entry */
+ {
+ prev_mfg_record->next = new_mfg_record;
+ mfg_record = prev_mfg_record->next;
+ }
+ }
+ else
+ first_mfg_record = mfg_record;
+ DBG_DBG ("update_mfg_record_list: created mfg %s\n", mfg_record->name);
+ } /* if (!mfg_record) */
+
+ /* create model entries */
+ while (model)
+ {
+ mfg_record->model_record =
+ update_model_record_list (mfg_record->model_record, model, be);
+ model = model->next;
+ }
+ return first_mfg_record;
+}
+
+/* Create a sorted list of manufacturers based on the backends list */
+static mfg_record_entry *
+create_mfg_list (device_type dev_type)
+{
+ mfg_record_entry *first_mfg_record = 0;
+ backend_entry *be = first_backend;
+
+ DBG_DBG ("create_mfg_list: start\n");
+ while (be)
+ {
+ type_entry *type = be->type;
+ while (type)
+ {
+ if (type->type == dev_type)
+ {
+ mfg_entry *mfg = type->mfg;
+ while (mfg)
+ {
+ first_mfg_record =
+ update_mfg_record_list (first_mfg_record, mfg, be);
+ mfg = mfg->next;
+ }
+ }
+ type = type->next;
+ }
+ be = be->next;
+ }
+ DBG_DBG ("create_mfg_list: exit\n");
+ return first_mfg_record;
+}
+
+/* Print an ASCII list with all the information we have */
+static void
+ascii_print_backends (void)
+{
+ backend_entry *be;
+
+ be = first_backend;
+ while (be)
+ {
+ url_entry *url = be->url;
+ type_entry *type = be->type;
+
+ if (be->name)
+ printf ("backend `%s'\n", be->name);
+ else
+ printf ("backend *none*\n");
+
+ if (be->version)
+ printf (" version `%s'\n", be->version);
+ else
+ printf (" version *none*\n");
+
+ if (be->new)
+ printf (" NEW!\n");
+
+ if (be->manpage)
+ printf (" manpage `%s'\n", be->manpage);
+ else
+ printf (" manpage *none*\n");
+
+ if (url)
+ while (url)
+ {
+ printf (" url `%s'\n", url->name);
+ url = url->next;
+ }
+ else
+ printf (" url *none*\n");
+
+ if (be->comment)
+ printf (" comment `%s'\n", be->comment);
+ else
+ printf (" comment *none*\n");
+
+ if (type)
+ while (type)
+ {
+ switch (type->type)
+ {
+ case type_scanner:
+ printf (" type scanner\n");
+ break;
+ case type_stillcam:
+ printf (" type stillcam\n");
+ break;
+ case type_vidcam:
+ printf (" type vidcam\n");
+ break;
+ case type_meta:
+ printf (" type meta\n");
+ break;
+ case type_api:
+ printf (" type api\n");
+ break;
+ default:
+ printf (" type *unknown*\n");
+ break;
+ }
+ if (type->desc)
+ {
+ url_entry *url = type->desc->url;
+ printf (" desc `%s'\n", type->desc->desc);
+ if (url)
+ while (url)
+ {
+ printf (" url `%s'\n", url->name);
+ url = url->next;
+ }
+ else
+ printf (" url *none*\n");
+
+ if (type->desc->comment)
+ printf (" comment `%s'\n", type->desc->comment);
+ else
+ printf (" comment *none*\n");
+ }
+ else if (type->type >= type_meta)
+ printf (" desc *none*\n");
+
+ if (type->mfg)
+ {
+ mfg_entry *mfg = type->mfg;
+ while (mfg)
+ {
+ model_entry *model = mfg->model;
+ url_entry *url = mfg->url;
+
+ printf (" mfg `%s'\n", mfg->name);
+ if (url)
+ while (url)
+ {
+ printf (" url `%s'\n", url->name);
+ url = url->next;
+ }
+ else
+ printf (" url *none*\n");
+
+ if (mfg->comment)
+ printf (" comment `%s'\n", mfg->comment);
+ else
+ printf (" comment *none*\n");
+
+ if (model)
+ while (model)
+ {
+ url_entry *url = model->url;
+ printf (" model `%s'\n", model->name);
+ if (model->interface)
+ printf (" interface `%s'\n", model->interface);
+ else
+ printf (" interface *none*\n");
+
+ if (model->usb_vendor_id)
+ printf (" usb-vendor-id `%s'\n", model->usb_vendor_id);
+ else
+ printf (" usb-vendor-id *none*\n");
+
+ if (model->usb_product_id)
+ printf (" usb-product-id `%s'\n", model->usb_product_id);
+ else
+ printf (" usb-product-id *none*\n");
+
+ switch (model->status)
+ {
+ case status_minimal:
+ printf (" status minimal\n");
+ break;
+ case status_basic:
+ printf (" status basic\n");
+ break;
+ case status_good:
+ printf (" status good\n");
+ break;
+ case status_complete:
+ printf (" status complete\n");
+ break;
+ case status_untested:
+ printf (" status untested\n");
+ break;
+ case status_unsupported:
+ printf (" status unsupported\n");
+ break;
+ default:
+ printf (" status *unknown*\n");
+ break;
+ }
+
+ if (url)
+ while (url)
+ {
+ printf (" url `%s'\n", url->name);
+ url = url->next;
+ }
+ else
+ printf (" url *none*\n");
+
+ if (model->comment)
+ printf (" comment `%s'\n", model->comment);
+ else
+ printf (" comment *none*\n");
+
+ model = model->next;
+ }
+ else
+ printf (" model *none*\n");
+
+ mfg = mfg->next;
+ } /* while (mfg) */
+ }
+ else if (type->type < type_meta)
+ printf (" mfg *none*\n");
+ type = type->next;
+ } /* while (type) */
+ else
+ printf (" type *none*\n");
+ be = be->next;
+ } /* while (be) */
+}
+
+
+static char *
+clean_string (char *c)
+{
+ /* not avoided characters */
+
+ char *aux;
+
+ aux = malloc (strlen (c) * sizeof (char) * 6);
+
+ *aux = '\0';
+
+ while (*c != '\0')
+ {
+
+ /*limit to printable ASCII only*/
+ if(*c < 0x20 || *c > 0x7e){
+ c++;
+ continue;
+ }
+
+ switch (*c)
+ {
+ case '<':
+ aux = strcat (aux, "&lt;");
+ break;
+ case '>':
+ aux = strcat (aux, "&gt;");
+ break;
+ case '\'':
+ aux = strcat (aux, "&apos;");
+ break;
+ case '&':
+ aux = strcat (aux, "&amp;");
+ break;
+ default:
+ aux = strncat (aux, c, 1);
+ }
+ c = c + 1;
+ }
+ return aux;
+}
+
+/* Print an XML list with all the information we have */
+static void
+xml_print_backends (void)
+{
+ backend_entry *be;
+
+ be = first_backend;
+ printf ("<backends>\n");
+ while (be)
+ {
+ url_entry *url = be->url;
+ type_entry *type = be->type;
+
+ if (be->name)
+ printf ("<backend name=\"%s\">\n", clean_string (be->name));
+ else
+ printf ("<backend name=\"*none\">\n");
+
+ if (be->version)
+ printf ("<version>%s</version> \n", clean_string (be->version));
+ else
+ printf ("<version>*none*</version>\n");
+
+ if (be->new)
+ printf ("<new state=\"yes\"/>\n");
+ else
+ printf ("<new state=\"no\"/>\n");
+
+
+ if (be->manpage)
+ printf (" <manpage>%s</manpage>\n", clean_string (be->manpage));
+ else
+ printf (" <manpage>*none*</manpage>\n");
+
+ if (url)
+ while (url)
+ {
+ printf (" <url>%s</url>\n", clean_string (url->name));
+ url = url->next;
+ }
+ else
+ printf (" <url>*none*</url>\n");
+
+ if (be->comment)
+ printf (" <comment>%s</comment>\n", clean_string (be->comment));
+ else
+ printf (" <comment>*none*</comment>\n");
+
+ if (type)
+ while (type)
+ {
+
+ switch (type->type)
+ {
+ case type_scanner:
+ printf (" <type def=\"scanner\">\n");
+ break;
+ case type_stillcam:
+ printf (" <type def=\"stillcam\">\n");
+ break;
+ case type_vidcam:
+ printf (" <type def=\"vidcam\">\n");
+ break;
+ case type_meta:
+ printf (" <type def=\"meta\">\n");
+ break;
+ case type_api:
+ printf (" <type def=\"api\">\n");
+ break;
+ default:
+ printf (" <type def=\"*unknown*\">\n");
+ break;
+ }
+ if (type->desc)
+ {
+ url_entry *url = type->desc->url;
+ printf (" <desc>%s</desc>\n",
+ clean_string (type->desc->desc));
+ if (url)
+ while (url)
+ {
+ printf (" <url>%s</url>\n", clean_string (url->name));
+ url = url->next;
+ }
+ else
+ printf (" <url>*none*</url>\n");
+
+ if (type->desc->comment)
+ printf (" <comment>%s</comment>\n",
+ clean_string (type->desc->comment));
+ else
+ printf (" <comment>*none*</comment>\n");
+ }
+ else if (type->type >= type_meta)
+ printf (" <desc>*none*</desc>\n");
+
+ if (type->mfg)
+ {
+ mfg_entry *mfg = type->mfg;
+ while (mfg)
+ {
+ model_entry *model = mfg->model;
+ url_entry *url = mfg->url;
+
+ printf (" <mfg name=\"%s\">\n", clean_string (mfg->name));
+ if (url)
+ while (url)
+ {
+ printf (" <url>`%s'</url>\n",
+ clean_string (url->name));
+ url = url->next;
+ }
+ else
+ printf (" <url>*none*</url>\n");
+
+ if (mfg->comment)
+ printf (" <comment>%s</comment>\n",
+ clean_string (mfg->comment));
+ else
+ printf (" <comment>*none*</comment>\n");
+
+ if (model)
+ while (model)
+ {
+ url_entry *url = model->url;
+ printf (" <model name=\"%s\">\n",
+ clean_string (model->name));
+ if (model->interface)
+ printf (" <interface>%s</interface>\n",
+ clean_string (model->interface));
+ else
+ printf (" <interface>*none*</interface>\n");
+
+ if (model->usb_vendor_id)
+ printf (" <usbvendorid>%s</usbvendorid>\n",
+ clean_string (model->usb_vendor_id));
+ else
+ printf (" <usbvendorid>*none*</usbvendorid>\n");
+ if (model->usb_product_id)
+ printf (" <usbproductid>%s</usbproductid>\n",
+ clean_string (model->usb_product_id));
+ else
+ printf (" <usbproductid>*none*</usbproductid>\n");
+
+ switch (model->status)
+ {
+ case status_minimal:
+ printf (" <status>minimal</status>\n");
+ break;
+ case status_basic:
+ printf (" <status>basic</status>\n");
+ break;
+ case status_good:
+ printf (" <status>good</status>\n");
+ break;
+ case status_complete:
+ printf (" <status>complete</status>\n");
+ break;
+ case status_untested:
+ printf (" <status>untested</status>\n");
+ break;
+ case status_unsupported:
+ printf (" <status>unsupported</status>\n");
+ break;
+ default:
+ printf (" <status>*unknown*</status>\n");
+ break;
+ }
+
+ if (url)
+ while (url)
+ {
+ printf (" <url>%s</url>\n",
+ clean_string (url->name));
+ url = url->next;
+ }
+ else
+ printf (" <url>*none*</url>\n");
+
+ if (model->comment)
+ printf (" <comment>%s</comment>\n",
+ clean_string (model->comment));
+ else
+ printf (" <comment>*none*</comment>\n");
+
+ model = model->next;
+ printf (" </model>\n");
+ } /* while (model) */
+ else
+ printf (" <model name=\"*none*\" />\n");
+
+ printf (" </mfg>\n");
+ mfg = mfg->next;
+ } /* while (mfg) */
+ }
+ else if (type->type < type_meta)
+ printf (" <mfg>*none*</mfg>\n");
+ type = type->next;
+ printf (" </type>\n");
+ } /* while (type) */
+ else
+ printf (" <type>*none*</type>\n");
+ printf ("</backend>\n");
+ be = be->next;
+
+ } /* while (be) */
+ printf ("</backends>\n");
+}
+
+/* calculate statistics about supported devices per device type*/
+static void
+calculate_statistics_per_type (device_type dev_type, statistics_type num)
+{
+ backend_entry *be = first_backend;
+
+ while (be)
+ {
+ type_entry *type = be->type;
+
+ while (type)
+ {
+ if (type->type == dev_type)
+ {
+ mfg_entry *mfg = type->mfg;
+ model_entry *model;
+
+ if (type->desc)
+ {
+ num[status_complete]++;
+ type = type->next;
+ continue;
+ }
+
+ if (!mfg)
+ {
+ type = type->next;
+ continue;
+ }
+
+ mfg = type->mfg;
+ while (mfg)
+ {
+ model = mfg->model;
+ if (model)
+ {
+ while (model)
+ {
+ enum status_entry status = model->status;
+ num[status]++;
+ model = model->next;
+ } /* while (model) */
+ } /* if (num_models) */
+ mfg = mfg->next;
+ } /* while (mfg) */
+ } /* if (type->type) */
+ type = type->next;
+ } /* while (type) */
+ be = be->next;
+ } /* while (be) */
+}
+
+static void
+html_print_statistics_cell (const char * color, int number)
+{
+ printf ("<td align=center><font color=%s>%d</font></td>\n",
+ color, number);
+}
+
+static void
+html_print_statistics_per_type (device_type dev_type)
+{
+ statistics_type num = {0, 0, 0, 0, 0, 0, 0};
+ status_entry status;
+
+ calculate_statistics_per_type (dev_type, num);
+ printf ("<tr>\n");
+ printf("<td align=center><a href=\"#%s\">%s</a></td>\n",
+ device_type_aname [dev_type], device_type_name [dev_type]);
+
+ html_print_statistics_cell
+ (COLOR_UNKNOWN,
+ num[status_minimal] + num[status_basic] + num[status_good] +
+ num[status_complete] + num[status_untested] + num[status_unsupported]);
+ if (dev_type == type_scanner || dev_type == type_stillcam
+ || dev_type == type_vidcam)
+ {
+ html_print_statistics_cell
+ (COLOR_UNKNOWN,
+ num[status_minimal] + num[status_basic] + num[status_good] +
+ num[status_complete]);
+ for (status = status_complete; status >= status_unsupported; status--)
+ html_print_statistics_cell (status_color [status], num [status]);
+ }
+ else
+ {
+ printf ("<td align=center colspan=7>n/a</td>\n");
+ }
+ printf ("</tr>\n");
+}
+
+/* print html statistcis */
+static void
+html_print_summary (void)
+{
+ device_type dev_type;
+ status_entry status;
+
+ printf ("<h2>Summary</h2>\n");
+ printf ("<table border=1>\n");
+ printf ("<tr bgcolor=E0E0FF>\n");
+ printf ("<th align=center rowspan=3>Device type</th>\n");
+ printf ("<th align=center colspan=8>Number of devices</th>\n");
+ printf ("</tr>\n");
+ printf ("<tr bgcolor=E0E0FF>\n");
+ printf ("<th align=center rowspan=2>Total</th>\n");
+ printf ("<th align=center colspan=5>Supported</th>\n");
+ printf ("<th align=center rowspan=2><font color=" COLOR_UNTESTED
+ ">%s</font></th>\n", status_name[status_untested]);
+ printf ("<th align=center rowspan=2><font color=" COLOR_UNSUPPORTED
+ ">%s</font></th>\n", status_name[status_unsupported]);
+ printf ("</tr>\n");
+ printf ("<tr bgcolor=E0E0FF>\n");
+ printf ("<th align=center>Sum</th>\n");
+ for (status = status_complete; status >= status_minimal; status--)
+ printf ("<th align=center><font color=%s>%s</font></th>\n",
+ status_color[status], status_name[status]);
+ printf ("</tr>\n");
+ for (dev_type = type_scanner; dev_type <= type_api; dev_type++)
+ html_print_statistics_per_type (dev_type);
+ printf ("</table>\n");
+}
+
+
+/* Generate a name used for <a name=...> HTML tags */
+static char *
+html_generate_anchor_name (device_type dev_type, char *manufacturer_name)
+{
+ char *name = malloc (strlen (manufacturer_name) + 1 + 2);
+ char *pointer = name;
+ char type_char;
+
+ if (!name)
+ {
+ DBG_ERR ("html_generate_anchor_name: couldn't malloc\n");
+ return 0;
+ }
+
+ switch (dev_type)
+ {
+ case type_scanner:
+ type_char = 'S';
+ break;
+ case type_stillcam:
+ type_char = 'C';
+ break;
+ case type_vidcam:
+ type_char = 'V';
+ break;
+ case type_meta:
+ type_char = 'M';
+ break;
+ case type_api:
+ type_char = 'A';
+ break;
+ default:
+ type_char = 'Z';
+ break;
+ }
+
+ snprintf (name, strlen (manufacturer_name) + 1 + 2, "%c-%s",
+ type_char, manufacturer_name);
+
+ while (*pointer)
+ {
+ if (!isalnum (*pointer))
+ *pointer = '-';
+ else
+ *pointer = toupper (*pointer);
+ pointer++;
+ }
+ return name;
+}
+
+
+/* Generate one table per backend of all backends providing models */
+/* of type dev_type */
+static void
+html_backends_split_table (device_type dev_type)
+{
+ backend_entry *be = first_backend;
+ SANE_Bool first = SANE_TRUE;
+
+ printf ("<p><b>Backends</b>: \n");
+ while (be) /* print link list */
+ {
+ type_entry *type = be->type;
+ SANE_Bool found = SANE_FALSE;
+
+ while (type)
+ {
+ if (type->type == dev_type)
+ found = SANE_TRUE;
+ type = type->next;
+ }
+ if (found)
+ {
+ if (!first)
+ printf (", \n");
+ first = SANE_FALSE;
+ printf ("<a href=\"#%s\">%s</a>",
+ html_generate_anchor_name (dev_type, be->name), be->name);
+ }
+ be = be->next;
+ }
+ be = first_backend;
+ if (first)
+ printf ("(none)\n");
+
+ printf ("</p>\n");
+
+
+ while (be)
+ {
+ type_entry *type = be->type;
+
+ while (type)
+ {
+ if (type->type == dev_type)
+ {
+ mfg_entry *mfg = type->mfg;
+ model_entry *model;
+
+ printf ("<h3><a name=\"%s\">Backend: %s\n",
+ html_generate_anchor_name (type->type, be->name),
+ be->name);
+
+ if (be->version || be->new)
+ {
+ printf ("(");
+ if (be->version)
+ {
+ printf ("%s", be->version);
+ if (be->new)
+ printf (", <font color=" COLOR_NEW ">NEW!</font>");
+ }
+ else
+ printf ("<font color=" COLOR_NEW ">NEW!</font>");
+ printf (")\n");
+ }
+ printf ("</a></h3>\n");
+
+ printf ("<p>\n");
+
+ if (be->url && be->url->name)
+ {
+ url_entry *url = be->url;
+ printf ("<b>Link(s):</b> \n");
+ while (url)
+ {
+ if (url != be->url)
+ printf (", ");
+ printf ("<a href=\"%s\">%s</a>", url->name, url->name);
+ url = url->next;
+ }
+ printf ("<br>\n");
+ }
+ if (be->manpage)
+ printf ("<b>Manual page:</b> <a href=\"" MAN_PAGE_LINK
+ "\">%s</a><br>\n", be->manpage, be->manpage);
+
+ if (be->comment)
+ printf ("<b>Comment:</b> %s<br>\n", be->comment);
+
+
+ if (type->desc)
+ {
+ if (type->desc->desc)
+ {
+ if (type->desc->url && type->desc->url->name)
+ printf ("<b>Description:</b> "
+ "<a href=\"%s\">%s</a><br>\n",
+ type->desc->url->name, type->desc->desc);
+ else
+ printf ("<b>Description:</b> %s<br>\n",
+ type->desc->desc);
+ }
+
+ if (type->desc->comment)
+ printf ("<b>Comment:</b> %s<br>\n", type->desc->comment);
+ printf ("</p>\n");
+ type = type->next;
+ continue;
+ }
+ printf ("</p>\n");
+
+ if (!mfg)
+ {
+ type = type->next;
+ continue;
+ }
+
+ printf ("<table border=1>\n");
+
+ printf ("<tr bgcolor=E0E0FF>\n");
+ printf ("<th align=center>Manufacturer</th>\n");
+ printf ("<th align=center>Model</th>\n");
+ printf ("<th align=center>Interface</th>\n");
+ printf ("<th align=center>USB id</th>\n");
+ printf ("<th align=center>Status</th>\n");
+ printf ("<th align=center>Comment</th>\n");
+ printf ("</tr>\n");
+
+ mfg = type->mfg;
+ while (mfg)
+ {
+ model = mfg->model;
+ if (model)
+ {
+ int num_models = 0;
+
+ while (model) /* count models for rowspan */
+ {
+ model = model->next;
+ num_models++;
+ }
+ model = mfg->model;
+ printf ("<tr>\n");
+ printf ("<td align=center rowspan=%d>\n", num_models);
+ if (mfg->url && mfg->url->name)
+ printf ("<a href=\"%s\">%s</a>\n", mfg->url->name,
+ mfg->name);
+ else
+ printf ("%s\n", mfg->name);
+
+ while (model)
+ {
+ enum status_entry status = model->status;
+
+ if (model != mfg->model)
+ printf ("<tr>\n");
+
+ if (model->url && model->url->name)
+ printf
+ ("<td align=center><a href=\"%s\">%s</a></td>\n",
+ model->url->name, model->name);
+ else
+ printf ("<td align=center>%s</td>\n",
+ model->name);
+
+ if (model->interface)
+ printf ("<td align=center>%s</td>\n",
+ model->interface);
+ else
+ printf ("<td align=center>?</td>\n");
+
+ if (model->usb_vendor_id && model->usb_product_id)
+ printf ("<td align=center>%s/%s</td>\n",
+ model->usb_vendor_id, model->usb_product_id);
+ else
+ printf ("<td align=center>&nbsp;</td>\n");
+
+ printf ("<td align=center><font color=%s>%s</font></td>\n",
+ status_color[status], status_name[status]);
+
+ if (model->comment && model->comment[0] != 0)
+ printf ("<td>%s</td>\n", model->comment);
+ else
+ printf ("<td>&nbsp;</td>\n");
+
+ model = model->next;
+ printf ("</tr>\n");
+ } /* while (model) */
+ } /* if (num_models) */
+ mfg = mfg->next;
+ } /* while (mfg) */
+ printf ("</table>\n");
+ } /* if (type->type) */
+ type = type->next;
+ } /* while (type) */
+ be = be->next;
+ } /* while (be) */
+ /* printf ("</table>\n"); */
+}
+
+/* Generate one table per manufacturer constructed of all backends */
+/* providing models of type dev_type */
+static void
+html_mfgs_table (device_type dev_type)
+{
+ mfg_record_entry *mfg_record = 0, *first_mfg_record = 0;
+
+ first_mfg_record = create_mfg_list (dev_type);
+ mfg_record = first_mfg_record;
+
+ printf ("<p><b>Manufacturers</b>: \n");
+ while (mfg_record)
+ {
+ if (mfg_record != first_mfg_record)
+ printf (", \n");
+ printf ("<a href=\"#%s\">%s</a>",
+ html_generate_anchor_name (type_unknown, mfg_record->name),
+ mfg_record->name);
+ mfg_record = mfg_record->next;
+ }
+ mfg_record = first_mfg_record;
+ if (!mfg_record)
+ printf ("(none)\n");
+ printf ("</p>\n");
+ while (mfg_record)
+ {
+ model_record_entry *model_record = mfg_record->model_record;
+
+ printf ("<h3><a name=\"%s\">Manufacturer: %s</a></h3>\n",
+ html_generate_anchor_name (type_unknown, mfg_record->name),
+ mfg_record->name);
+ printf ("<p>\n");
+ if (mfg_record->url && mfg_record->url->name)
+ {
+ url_entry *url = mfg_record->url;
+ printf ("<b>Link(s):</b> \n");
+ while (url)
+ {
+ if (url != mfg_record->url)
+ printf (", ");
+ printf ("<a href=\"%s\">%s</a>", url->name, url->name);
+ url = url->next;
+ }
+ printf ("<br>\n");
+ }
+ if (mfg_record->comment)
+ printf ("<b>Comment:</b> %s<br>\n", mfg_record->comment);
+ printf ("</p>\n");
+ if (!model_record)
+ {
+ mfg_record = mfg_record->next;
+ continue;
+ }
+ printf ("<table border=1>\n");
+ printf ("<tr bgcolor=E0E0FF>\n");
+
+ printf ("<th align=center>Model</th>\n");
+ printf ("<th align=center>Interface</th>\n");
+ printf ("<th align=center>USB id</th>\n");
+ printf ("<th align=center>Status</th>\n");
+ printf ("<th align=center>Comment</th>\n");
+ printf ("<th align=center>Backend</th>\n");
+ printf ("<th align=center>Manpage</th>\n");
+ printf ("</tr>\n");
+
+ while (model_record)
+ {
+ enum status_entry status = model_record->status;
+
+ if (model_record->url && model_record->url->name)
+ printf ("<tr><td align=center><a "
+ "href=\"%s\">%s</a></td>\n",
+ model_record->url->name, model_record->name);
+ else
+ printf ("<tr><td align=center>%s</td>\n", model_record->name);
+
+ if (model_record->interface)
+ printf ("<td align=center>%s</td>\n", model_record->interface);
+ else
+ printf ("<td align=center>?</td>\n");
+
+ if (model_record->usb_vendor_id && model_record->usb_product_id)
+ printf ("<td align=center>%s/%s</td>\n",
+ model_record->usb_vendor_id, model_record->usb_product_id);
+ else
+ printf ("<td align=center>&nbsp;</td>\n");
+
+ printf ("<td align=center><font color=%s>%s</font></td>\n",
+ status_color[status], status_name[status]);
+
+ if (model_record->comment && model_record->comment[0] != 0)
+ printf ("<td>%s</td>\n", model_record->comment);
+ else
+ printf ("<td>&nbsp;</td>\n");
+
+ printf ("<td align=center>\n");
+ if (model_record->be->url && model_record->be->url->name)
+ printf ("<a href=\"%s\">%s</a>\n",
+ model_record->be->url->name, model_record->be->name);
+ else
+ printf ("%s", model_record->be->name);
+
+ if (model_record->be->version || model_record->be->new)
+ {
+ printf ("<br>(");
+ if (model_record->be->version)
+ {
+ printf ("%s", model_record->be->version);
+ if (model_record->be->new)
+ printf (", <font color=" COLOR_NEW ">NEW!</font>");
+ }
+ else
+ printf ("<font color=" COLOR_NEW ">NEW!</font>");
+ printf (")\n");
+ }
+
+ printf ("</td>\n");
+ if (model_record->be->manpage)
+ printf ("<td align=center><a href=\""
+ MAN_PAGE_LINK "\">%s</a></td>\n",
+ model_record->be->manpage, model_record->be->manpage);
+ else
+ printf ("<td align=center>?</td>\n");
+
+ printf ("</tr>\n");
+ model_record = model_record->next;
+ } /* while model_record */
+ printf ("</table>\n");
+ mfg_record = mfg_record->next;
+ } /* while mfg_record */
+}
+
+/* Print the HTML headers and an introduction */
+static void
+html_print_header (void)
+{
+ printf
+ ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
+ "<html> <head>\n"
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; "
+ "charset=iso-8859-1\">\n");
+ printf ("<title>%s</title>\n", title);
+ printf
+ ("</head>\n"
+ "<body bgcolor=FFFFFF>\n"
+ "<div align=center>\n"
+ "<img src=\"http://www.sane-project.org/images/sane.png\" alt=\"SANE\">\n");
+ printf ("<h1>%s</h1>\n", title);
+ printf ("</div>\n" "<hr>\n");
+ printf ("%s\n", intro);
+ printf
+ ("<p>This is only a summary!\n"
+ "Please consult the manpages and the author-supplied webpages\n"
+ "for more detailed (and usually important) information\n"
+ "concerning each backend.</p>\n");
+ printf
+ ("<p>If you have new information or corrections, please file a\n"
+ "<a href=\"http://www.sane-project.org/bugs.html\">bug report</a>\n"
+ "with as many details as possible. Also please tell us if your scanner \n"
+ "isn't mentioned in this list at all.</p>\n"
+ "<p>For an explanation of the tables, see the\n"
+ "<a href=\"#legend\">legend</a>.\n");
+}
+
+/* Print the HTML footers and contact information */
+static void
+html_print_footer (void)
+{
+ time_t current_time = time (0);
+
+ printf
+ ("<hr>\n"
+ "<a href=\"http://www.sane-project.org/\">SANE homepage</a>\n"
+ "<address>\n"
+ "<a href=\"http://www.sane-project.org/imprint.html\"\n"
+ ">Contact</a>\n" "</address>\n" "<font size=-1>\n");
+ printf ("This page was last updated on %s by sane-desc %s from %s\n",
+ asctime (localtime (&current_time)), SANE_DESC_VERSION, PACKAGE_STRING);
+ printf ("</font>\n");
+ printf ("</body> </html>\n");
+}
+
+
+/* print parts of the legend */
+static void
+html_print_legend_backend (void)
+{
+ printf
+ (" <dt><b>Backend:</b></dt>\n"
+ " <dd>Name of the backend, in parentheses if available:\n"
+ " Version of backend/driver; newer versions may be\n"
+ " available from their home sites.<br>"
+ " <font color=" COLOR_NEW ">NEW!</font> means brand-new to the\n"
+ " current release of SANE.<br>\n"
+ " UNMAINTAINED means that nobody maintains that backend. Expect no \n"
+ " new features or newly supported devices. You are welcome to take over \n"
+ " maintainership.\n" " </dd>\n");
+}
+
+static void
+html_print_legend_link (void)
+{
+ printf
+ (" <dt><b>Link(s):</b></dt>\n"
+ " <dd>Link(s) to more extensive and\n"
+ " detailed information, if it exists, or the email address\n"
+ " of the author or maintainer.\n");
+}
+
+static void
+html_print_legend_manual (void)
+{
+ printf
+ (" <dt><b>Manual Page:</b></dt>\n"
+ " <dd>A link to the man-page online, if it exists.</dd>\n");
+}
+
+static void
+html_print_legend_comment (void)
+{
+ printf
+ (" <dt><b>Comment:</b></dt>\n"
+ " <dd>More information about the backend or model, e.g. the level of "
+ " support and possible problems.</dd>\n");
+}
+
+static void
+html_print_legend_manufacturer (void)
+{
+ printf
+ (" <dt><b>Manufacturer:</b></dt>\n"
+ " <dd>Manufacturer, vendor or brand name of the device.</dd>\n");
+}
+
+static void
+html_print_legend_model (void)
+{
+ printf
+ (" <dt><b>Model:</b></dt>\n" " <dd>Name of the the device.</dd>\n");
+}
+
+static void
+html_print_legend_interface (void)
+{
+ printf
+ (" <dt><b>Interface:</b></dt>\n"
+ " <dd>How the device is connected to the computer.</dd>\n");
+}
+
+static void
+html_print_legend_usbid (void)
+{
+ printf
+ (" <dt><b>USB id:</b></dt>\n"
+ " <dd>The USB vendor and product ids as printed by sane-find-scanner -q (only applicable for USB devices).</dd>\n");
+}
+
+static void
+html_print_legend_status (void)
+{
+ printf
+ (" <dt><b>Status</b>:</dt>\n"
+ " <dd>Indicates how many of the features the device provides \n"
+ " are supported by SANE.\n"
+ " <ul><li><font color=" COLOR_UNSUPPORTED ">unsupported</font>"
+ " means the device is not supported at least by this backend. "
+ " It may be supported by other backends, however.\n");
+ printf
+ (" <li><font color=" COLOR_UNTESTED ">untested</font> means the "
+ " device may be supported but couldn't be tested. Be very "
+ " careful and report success/failure.\n"
+ " <li><font color=" COLOR_MINIMAL ">minimal</font> means that the\n"
+ " device is detected and scans at least in one mode. But the quality \n"
+ " is bad or important features won't work.\n");
+ printf
+ (" <li><font color=" COLOR_BASIC ">basic</font> means it works at \n"
+ " least in the most important modes but quality is not perfect.\n"
+ " <li><font color=" COLOR_GOOD
+ ">good</font> means the device is usable \n"
+ " for day-to-day work. Some rather exotic features may be missing.\n"
+ " <li><font color=" COLOR_COMPLETE
+ ">complete</font> means the backends \n"
+ " supports everything the device can do.\n" " </ul></dd>\n");
+}
+
+static void
+html_print_legend_description (void)
+{
+ printf
+ (" <dt><b>Description</b>:</dt>\n"
+ " <dd>The scope of application of the backend.\n");
+}
+
+/* Print the HTML page with one table of models per backend */
+static void
+html_print_backends_split (void)
+{
+ if (!title)
+ title = "SANE: Backends (Drivers)";
+ if (!intro)
+ intro = "<p> The following table summarizes the backends/drivers "
+ "distributed with the latest version of sane-backends, and the hardware "
+ "or software they support. </p>";
+
+ html_print_header ();
+
+ html_print_summary ();
+
+ printf ("<h2><a name=\"SCANNERS\">Scanners</a></h2>\n");
+ html_backends_split_table (type_scanner);
+
+ printf ("<h2><a name=\"STILL\">Still Cameras</a></h2>\n");
+ html_backends_split_table (type_stillcam);
+
+ printf ("<h2><a name=\"VIDEO\">Video Cameras</a></h2>\n");
+ html_backends_split_table (type_vidcam);
+
+ printf ("<h2><a name=\"API\">APIs</a></h2>\n");
+ html_backends_split_table (type_api);
+
+ printf ("<h2><a name=\"META\">Meta Backends</a></h2>\n");
+ html_backends_split_table (type_meta);
+
+ printf ("<h3><a name=\"legend\">Legend:</a></h3>\n" "<blockquote><dl>\n");
+
+ html_print_legend_backend ();
+ html_print_legend_link ();
+ html_print_legend_manual ();
+ html_print_legend_comment ();
+ html_print_legend_manufacturer ();
+ html_print_legend_model ();
+ html_print_legend_interface ();
+ html_print_legend_usbid ();
+ html_print_legend_status ();
+ html_print_legend_description ();
+
+ printf ("</dl></blockquote>\n");
+
+ html_print_footer ();
+}
+
+/* Print the HTML page with one table of models per manufacturer */
+static void
+html_print_mfgs (void)
+{
+ if (!title)
+ title = "SANE: Supported Devices";
+
+ if (!intro)
+ intro = "<p> The following table summarizes the devices supported "
+ "by the latest version of sane-backends. </p>";
+
+ html_print_header ();
+
+ html_print_summary ();
+
+ printf ("<h2><a name=\"SCANNERS\">Scanners</a></h2>\n");
+ html_mfgs_table (type_scanner);
+
+ printf ("<h2><a name=\"STILL\">Still Cameras</a></h2>\n");
+ html_mfgs_table (type_stillcam);
+
+ printf ("<h2><a name=\"VIDEO\">Video Cameras</a></h2>\n");
+ html_mfgs_table (type_vidcam);
+
+ printf ("<h2><a name=\"API\">APIs</a></h2>\n");
+ html_backends_split_table (type_api);
+
+ printf ("<h2><a name=\"META\">Meta Backends</a></h2>\n");
+ html_backends_split_table (type_meta);
+
+ printf
+ ("<h3><a name=\"legend\">Legend:</a></h3>\n" "<blockquote>\n" "<dl>\n");
+
+ html_print_legend_model ();
+ html_print_legend_interface ();
+ html_print_legend_usbid ();
+ html_print_legend_status ();
+ html_print_legend_comment ();
+ html_print_legend_backend ();
+ html_print_legend_manual ();
+
+ html_print_legend_manufacturer ();
+ html_print_legend_description ();
+
+ printf ("</dl>\n" "</blockquote>\n");
+
+ html_print_footer ();
+}
+
+
+/* print statistics about supported devices */
+static void
+print_statistics_per_type (device_type dev_type)
+{
+ statistics_type num = {0, 0, 0, 0, 0, 0, 0};
+
+ calculate_statistics_per_type (dev_type, num);
+
+ printf (" Total: %4d\n",
+ num[status_minimal] + num[status_basic] + num[status_good] +
+ num[status_complete] + num[status_untested] + num[status_untested] +
+ num[status_unsupported]);
+ if (dev_type == type_scanner || dev_type == type_stillcam
+ || dev_type == type_vidcam)
+ {
+ printf (" Supported: %4d (complete: %d, good: %d, basic: %d, "
+ "minimal: %d)\n",
+ num[status_minimal] + num[status_basic] + num[status_good] +
+ num[status_complete], num[status_complete], num[status_good],
+ num[status_basic], num[status_minimal]);
+ printf (" Untested: %4d\n", num[status_untested]);
+ printf (" Unsupported: %4d\n", num[status_unsupported]);
+ }
+}
+
+static void
+print_statistics (void)
+{
+ printf ("Number of known devices:\n");
+ printf ("Scanners:\n");
+ print_statistics_per_type (type_scanner);
+ printf ("Still cameras:\n");
+ print_statistics_per_type (type_stillcam);
+ printf ("Video cameras:\n");
+ print_statistics_per_type (type_vidcam);
+ printf ("Meta backends:\n");
+ print_statistics_per_type (type_meta);
+ printf ("API backends:\n");
+ print_statistics_per_type (type_api);
+}
+
+static usbid_type *
+create_usbid (char *manufacturer, char *model,
+ char *usb_vendor_id, char *usb_product_id)
+{
+ usbid_type * usbid = calloc (1, sizeof (usbid_type));
+
+ usbid->usb_vendor_id = strdup (usb_vendor_id);
+ usbid->usb_product_id = strdup (usb_product_id);
+ usbid->name = calloc (1, sizeof (manufacturer_model_type));
+ usbid->name->name = calloc (1, strlen (manufacturer) + strlen (model) + 3);
+ sprintf (usbid->name->name, "%s %s", manufacturer, model);
+ usbid->name->next = 0;
+ usbid->next = 0;
+ DBG_DBG ("New USB ids: %s/%s (%s %s)\n", usb_vendor_id, usb_product_id,
+ manufacturer, model);
+ return usbid;
+}
+
+static scsiid_type *
+create_scsiid (char *manufacturer, char *model,
+ char *scsi_vendor_id, char *scsi_product_id, SANE_Bool is_processor)
+{
+ scsiid_type * scsiid = calloc (1, sizeof (scsiid_type));
+
+ scsiid->scsi_vendor_id = strdup (scsi_vendor_id);
+ scsiid->scsi_product_id = strdup (scsi_product_id);
+ scsiid->is_processor = is_processor;
+ scsiid->name = calloc (1, sizeof (manufacturer_model_type));
+ scsiid->name->name = calloc (1, strlen (manufacturer) + strlen (model) + 3);
+ sprintf (scsiid->name->name, "%s %s", manufacturer, model);
+ scsiid->name->next = 0;
+ scsiid->next = 0;
+ DBG_DBG ("New SCSI ids: %s/%s (%s %s)\n", scsi_vendor_id, scsi_product_id,
+ manufacturer, model);
+ return scsiid;
+}
+
+static usbid_type *
+add_usbid (usbid_type *first_usbid, char *manufacturer, char *model,
+ char *usb_vendor_id, char *usb_product_id)
+{
+ usbid_type *usbid = first_usbid;
+ usbid_type *prev_usbid = 0, *tmp_usbid = 0;
+
+ if (!first_usbid)
+ first_usbid = create_usbid (manufacturer, model, usb_vendor_id, usb_product_id);
+ else
+ {
+ while (usbid)
+ {
+ if (strcmp (usb_vendor_id, usbid->usb_vendor_id) == 0 &&
+ strcmp (usb_product_id, usbid->usb_product_id) == 0)
+ {
+ manufacturer_model_type *man_mod = usbid->name;
+
+ while (man_mod->next)
+ man_mod = man_mod->next;
+ man_mod->next = malloc (sizeof (manufacturer_model_type));
+ man_mod->next->name = malloc (strlen (manufacturer) + strlen (model) + 3);
+ sprintf (man_mod->next->name, "%s %s", manufacturer, model);
+ man_mod->next->next = 0;
+ DBG_DBG ("Added manufacturer/model %s %s to USB ids %s/%s\n", manufacturer, model,
+ usb_vendor_id, usb_product_id);
+ break;
+ }
+ if (strcmp (usb_vendor_id, usbid->usb_vendor_id) < 0 ||
+ (strcmp (usb_vendor_id, usbid->usb_vendor_id) == 0 &&
+ strcmp (usb_product_id, usbid->usb_product_id) < 0))
+ {
+
+ tmp_usbid = create_usbid (manufacturer, model, usb_vendor_id, usb_product_id);
+ tmp_usbid->next = usbid;
+ if (prev_usbid)
+ prev_usbid->next = tmp_usbid;
+ else
+ first_usbid = tmp_usbid;
+ break;
+ }
+ prev_usbid = usbid;
+ usbid = usbid->next;
+ }
+ if (!usbid)
+ {
+ prev_usbid->next = create_usbid (manufacturer, model, usb_vendor_id, usb_product_id);
+ usbid = prev_usbid->next;
+ }
+ }
+ return first_usbid;
+}
+
+static scsiid_type *
+add_scsiid (scsiid_type *first_scsiid, char *manufacturer, char *model,
+ char *scsi_vendor_id, char *scsi_product_id, SANE_Bool is_processor)
+{
+ scsiid_type *scsiid = first_scsiid;
+ scsiid_type *prev_scsiid = 0, *tmp_scsiid = 0;
+
+ if (!first_scsiid)
+ first_scsiid = create_scsiid (manufacturer, model, scsi_vendor_id, scsi_product_id, is_processor);
+ else
+ {
+ while (scsiid)
+ {
+ if (strcmp (scsi_vendor_id, scsiid->scsi_vendor_id) == 0 &&
+ strcmp (scsi_product_id, scsiid->scsi_product_id) == 0)
+ {
+ manufacturer_model_type *man_mod = scsiid->name;
+
+ while (man_mod->next)
+ man_mod = man_mod->next;
+ man_mod->next = malloc (sizeof (manufacturer_model_type));
+ man_mod->next->name = malloc (strlen (manufacturer) + strlen (model) + 3);
+ sprintf (man_mod->next->name, "%s %s", manufacturer, model);
+ man_mod->next->next = 0;
+ DBG_DBG ("Added manufacturer/model %s %s to SCSI ids %s/%s\n", manufacturer, model,
+ scsi_vendor_id, scsi_product_id);
+ break;
+ }
+ if (strcmp (scsi_vendor_id, scsiid->scsi_vendor_id) < 0 ||
+ (strcmp (scsi_vendor_id, scsiid->scsi_vendor_id) == 0 &&
+ strcmp (scsi_product_id, scsiid->scsi_product_id) < 0))
+ {
+
+ tmp_scsiid = create_scsiid (manufacturer, model, scsi_vendor_id, scsi_product_id, is_processor);
+ tmp_scsiid->next = scsiid;
+ if (prev_scsiid)
+ prev_scsiid->next = tmp_scsiid;
+ else
+ first_scsiid = tmp_scsiid;
+ break;
+ }
+ prev_scsiid = scsiid;
+ scsiid = scsiid->next;
+ }
+ if (!scsiid)
+ {
+ prev_scsiid->next = create_scsiid (manufacturer, model, scsi_vendor_id, scsi_product_id, is_processor);
+ scsiid = prev_scsiid->next;
+ }
+ }
+ return first_scsiid;
+}
+
+static usbid_type *
+create_usbids_table (void)
+{
+ backend_entry *be;
+ usbid_type *first_usbid = NULL;
+
+ if (!first_backend)
+ return NULL;
+
+ for (be = first_backend; be; be = be->next)
+ {
+ type_entry *type;
+
+ if (!be->type)
+ continue;
+
+ for (type = be->type; type; type = type->next)
+ {
+ mfg_entry *mfg;
+
+ if (!type->mfg)
+ continue;
+
+ for (mfg = type->mfg; mfg; mfg = mfg->next)
+ {
+ model_entry *model;
+
+ if (!mfg->model)
+ continue;
+
+ for (model = mfg->model; model; model = model->next)
+ {
+ if ((model->status == status_unsupported)
+ || (model->status == status_unknown))
+ continue;
+
+ if (model->usb_vendor_id && model->usb_product_id)
+ {
+ first_usbid = add_usbid (first_usbid, mfg->name,
+ model->name,
+ model->usb_vendor_id,
+ model->usb_product_id);
+ }
+ } /* for (model) */
+ } /* for (mfg) */
+ } /* for (type) */
+ } /* for (be) */
+
+ return first_usbid;
+}
+
+static scsiid_type *
+create_scsiids_table (void)
+{
+ backend_entry *be;
+ scsiid_type *first_scsiid = NULL;
+
+ if (!first_backend)
+ return NULL;
+
+ for (be = first_backend; be; be = be->next)
+ {
+ type_entry *type;
+
+ if (!be->type)
+ continue;
+
+ for (type = be->type; type; type = type->next)
+ {
+ mfg_entry *mfg;
+
+ if (!type->mfg)
+ continue;
+
+ for (mfg = type->mfg; mfg; mfg = mfg->next)
+ {
+ model_entry *model;
+
+ if (!mfg->model)
+ continue;
+
+ for (model = mfg->model; model; model = model->next)
+ {
+ if ((model->status == status_unsupported)
+ || (model->status == status_unknown))
+ continue;
+
+ if (model->scsi_vendor_id && model->scsi_product_id)
+ {
+ first_scsiid = add_scsiid (first_scsiid, mfg->name,
+ model->name,
+ model->scsi_vendor_id,
+ model->scsi_product_id,
+ model->scsi_is_processor);
+ }
+ } /* for (model) */
+ } /* for (mfg) */
+ } /* for (type) */
+ } /* for (be) */
+
+ return first_scsiid;
+}
+
+/* print USB usermap file to be used by the hotplug tools */
+static void
+print_usermap_header (void)
+{
+ time_t current_time = time (0);
+
+ printf
+ ("# This file was automatically created based on description files (*.desc)\n"
+ "# by sane-desc %s from %s on %s"
+ "#\n"
+ ,
+ SANE_DESC_VERSION, PACKAGE_STRING, asctime (localtime (&current_time)));
+
+ printf
+ ("# The entries below are used to detect a USB device and change owner\n"
+ "# and permissions on the \"device node\" used by libusb.\n"
+ "#\n"
+ "# The 0x0003 match flag means the device is matched by its vendor and\n"
+ "# product IDs.\n"
+ "#\n"
+ "# Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID\n"
+ "# respectively):\n"
+ "#\n"
+ );
+
+ printf
+ ("# libusbscanner 0x0003 0xVVVV 0xPPPP 0x0000 0x0000 0x00 0x00 0x00 0x00 "
+ "0x00 0x00 0x00000000\n"
+ "# usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi "
+ "bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass "
+ "bInterfaceSubClass bInterfaceProtocol driver_info\n"
+ "#\n"
+ );
+
+ printf
+ ("# If your scanner isn't listed below, you can add it as explained above.\n"
+ "#\n"
+ "# If your scanner is supported by some external backend (brother, epkowa,\n"
+ "# hpaio, etc) please ask the author of the backend to provide proper\n"
+ "# device detection support for your OS\n"
+ "#\n"
+ "# If the scanner is supported by sane-backends, please mail the entry to\n"
+ "# the sane-devel mailing list (sane-devel@lists.alioth.debian.org).\n"
+ "#\n"
+ );
+
+}
+
+static void
+print_usermap (void)
+{
+ usbid_type *usbid = create_usbids_table ();
+
+ print_usermap_header ();
+ while (usbid)
+ {
+ manufacturer_model_type * name = usbid->name;
+
+ printf ("# ");
+ while (name)
+ {
+ if (name != usbid->name)
+ printf (" | ");
+ printf ("%s", name->name);
+ name = name->next;
+ }
+ printf ("\n");
+ printf ("libusbscanner 0x0003 %s %s ", usbid->usb_vendor_id,
+ usbid->usb_product_id);
+ printf ("0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000\n");
+ usbid = usbid->next;
+ }
+}
+
+/* print libsane.db file for hotplug-ng */
+static void
+print_db_header (void)
+{
+ time_t current_time = time (0);
+ printf ("# This file was automatically created based on description files (*.desc)\n"
+ "# by sane-desc %s from %s on %s",
+ SANE_DESC_VERSION, PACKAGE_STRING, asctime (localtime (&current_time)));
+ printf
+ ("#\n"
+ "# The entries below are used to detect a USB device when it's plugged in\n"
+ "# and then run a script to change the ownership and\n"
+ "# permissions on the \"device node\" used by libusb.\n"
+ "# Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID\n"
+ "# respectively):\n");
+ printf
+ ("#\n"
+ "# 0xVVVV<tab>0xPPPP<tab>%s:%s<tab>%s<tab>[/usr/local/bin/foo.sh]\n"
+ "# Fields:\n"
+ "# vendor ID\n"
+ "# product ID\n"
+ "# ownership (user:group)\n"
+ "# permissions\n"
+ "# path of an optional script to run (it can be omitted)\n"
+ "#\n"
+ , DEVOWNER, DEVGROUP, DEVMODE);
+
+ printf
+ ("# If your scanner isn't listed below, you can add it as explained above.\n"
+ "#\n"
+ "# If your scanner is supported by some external backend (brother, epkowa,\n"
+ "# hpaio, etc) please ask the author of the backend to provide proper\n"
+ "# device detection support for your OS\n"
+ "#\n"
+ "# If the scanner is supported by sane-backends, please mail the entry to\n"
+ "# the sane-devel mailing list (sane-devel@lists.alioth.debian.org).\n"
+ "#\n"
+ );
+}
+
+static void
+print_db (void)
+{
+ usbid_type *usbid = create_usbids_table ();
+
+ print_db_header ();
+ while (usbid)
+ {
+ manufacturer_model_type * name = usbid->name;
+
+ printf ("# ");
+ while (name)
+ {
+ if (name != usbid->name)
+ printf (" | ");
+ printf ("%s", name->name);
+ name = name->next;
+ }
+ printf ("\n");
+ printf ("%s\t%s\t%s:%s\t%s\t\n", usbid->usb_vendor_id,
+ usbid->usb_product_id, DEVOWNER, DEVGROUP, DEVMODE);
+ usbid = usbid->next;
+ }
+}
+
+/* print libsane.rules for Linux udev */
+static void
+print_udev_header (void)
+{
+ time_t current_time = time (0);
+ printf ("# This file was automatically created based on description files (*.desc)\n"
+ "# by sane-desc %s from %s on %s",
+ SANE_DESC_VERSION, PACKAGE_STRING, asctime (localtime (&current_time)));
+
+ printf
+ ("#\n"
+ "# udev rules file for supported USB and SCSI devices\n"
+ "#\n"
+ "# The SCSI device support is very basic and includes only\n"
+ "# scanners that mark themselves as type \"scanner\" or\n"
+ "# SCSI-scanners from HP and other vendors that are entitled \"processor\"\n"
+ "# but are treated accordingly.\n"
+ "#\n");
+ printf
+ ("# To add a USB device, add a rule to the list below between the\n"
+ "# LABEL=\"libsane_usb_rules_begin\" and LABEL=\"libsane_usb_rules_end\" lines.\n"
+ "#\n"
+ "# To run a script when your device is plugged in, add RUN+=\"/path/to/script\"\n"
+ "# to the appropriate rule.\n"
+ "#\n"
+ );
+ printf
+ ("# If your scanner isn't listed below, you can add it as explained above.\n"
+ "#\n"
+ "# If your scanner is supported by some external backend (brother, epkowa,\n"
+ "# hpaio, etc) please ask the author of the backend to provide proper\n"
+ "# device detection support for your OS\n"
+ "#\n"
+ "# If the scanner is supported by sane-backends, please mail the entry to\n"
+ "# the sane-devel mailing list (sane-devel@lists.alioth.debian.org).\n"
+ "#\n"
+ );
+}
+
+static void
+print_udev (void)
+{
+ usbid_type *usbid = create_usbids_table ();
+ scsiid_type *scsiid = create_scsiids_table ();
+ int i;
+
+ print_udev_header ();
+ printf("ACTION!=\"add\", GOTO=\"libsane_rules_end\"\n"
+ "ENV{DEVTYPE}==\"usb_device\", GOTO=\"libsane_create_usb_dev\"\n"
+ "SUBSYSTEMS==\"scsi\", GOTO=\"libsane_scsi_rules_begin\"\n"
+ "SUBSYSTEM==\"usb_device\", GOTO=\"libsane_usb_rules_begin\"\n"
+ "SUBSYSTEM!=\"usb_device\", GOTO=\"libsane_usb_rules_end\"\n"
+ "\n");
+
+ printf("# Kernel >= 2.6.22 jumps here\n"
+ "LABEL=\"libsane_create_usb_dev\"\n"
+ "\n");
+
+ printf("# For Linux >= 2.6.22 without CONFIG_USB_DEVICE_CLASS=y\n"
+ "# If the following rule does not exist on your system yet, uncomment it\n"
+ "# ENV{DEVTYPE}==\"usb_device\", "
+ "MODE=\"0664\", OWNER=\"root\", GROUP=\"root\"\n"
+ "\n");
+
+ printf("# Kernel < 2.6.22 jumps here\n"
+ "LABEL=\"libsane_usb_rules_begin\"\n"
+ "\n");
+
+ while (usbid)
+ {
+ manufacturer_model_type * name = usbid->name;
+
+ i = 0;
+ printf ("# ");
+ while (name)
+ {
+ if ((name != usbid->name) && (i > 0))
+ printf (" | ");
+ printf ("%s", name->name);
+ name = name->next;
+
+ i++;
+
+ /*
+ * Limit the number of model names on the same line to 3,
+ * as udev cannot handle very long lines and prints a warning
+ * message while loading the rules files.
+ */
+ if ((i == 3) && (name != NULL))
+ {
+ printf("\n# ");
+ i = 0;
+ }
+ }
+ printf ("\n");
+
+ if (mode == output_mode_udevacl)
+ printf ("ATTRS{idVendor}==\"%s\", ATTRS{idProduct}==\"%s\", ENV{libsane_matched}=\"yes\"\n",
+ usbid->usb_vendor_id + 2, usbid->usb_product_id + 2);
+ else
+ printf ("ATTRS{idVendor}==\"%s\", ATTRS{idProduct}==\"%s\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n",
+ usbid->usb_vendor_id + 2, usbid->usb_product_id + 2, DEVMODE, DEVGROUP);
+
+ usbid = usbid->next;
+ }
+
+ printf("\n# The following rule will disable USB autosuspend for the device\n");
+ printf("ENV{libsane_matched}==\"yes\", RUN+=\"/bin/sh -c 'if test -e /sys/$env{DEVPATH}/power/control; then echo on > /sys/$env{DEVPATH}/power/control; elif test -e /sys/$env{DEVPATH}/power/level; then echo on > /sys/$env{DEVPATH}/power/level; fi'\"\n");
+
+ printf ("\nLABEL=\"libsane_usb_rules_end\"\n\n");
+
+ printf ("SUBSYSTEMS!=\"scsi\", GOTO=\"libsane_scsi_rules_end\"\n\n");
+ printf ("LABEL=\"libsane_scsi_rules_begin\"\n");
+ printf ("# Generic: SCSI device type 6 indicates a scanner\n");
+
+ if (mode == output_mode_udevacl)
+ printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"6\", ENV{libsane_matched}=\"yes\"\n");
+ else
+ printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"6\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n", DEVMODE, DEVGROUP);
+
+
+ printf ("# Some scanners advertise themselves as SCSI device type 3\n");
+
+ printf ("# Wildcard: for some Epson SCSI scanners\n");
+ if (mode == output_mode_udevacl)
+ printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"EPSON\", ATTRS{model}==\"SCANNER*\", ENV{libsane_matched}=\"yes\"\n");
+ else
+ printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"EPSON\", ATTRS{model}==\"SCANNER*\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n",
+ DEVMODE, DEVGROUP);
+
+ while (scsiid)
+ {
+ manufacturer_model_type * name = scsiid->name;
+
+ if (!scsiid->is_processor)
+ {
+ scsiid = scsiid->next;
+ continue;
+ }
+
+ /* Wildcard for Epson scanners: vendor = EPSON, product = SCANNER* */
+ if ((strcmp(scsiid->scsi_vendor_id, "EPSON") == 0)
+ && (strncmp(scsiid->scsi_product_id, "SCANNER", 7) == 0))
+ {
+ scsiid = scsiid->next;
+ continue;
+ }
+
+ i = 0;
+ printf ("# ");
+ while (name)
+ {
+ if ((name != scsiid->name) && (i > 0))
+ printf (" | ");
+ printf ("%s", name->name);
+ name = name->next;
+
+ i++;
+
+ /*
+ * Limit the number of model names on the same line to 3,
+ * as udev cannot handle very long lines and prints a warning
+ * message while loading the rules files.
+ */
+ if ((i == 3) && (name != NULL))
+ {
+ printf("\n# ");
+ i = 0;
+ }
+ }
+ printf ("\n");
+
+ if (mode == output_mode_udevacl)
+ printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"%s\", ATTRS{model}==\"%s\", ENV{libsane_matched}=\"yes\"\n",
+ scsiid->scsi_vendor_id, scsiid->scsi_product_id);
+ else
+ printf ("KERNEL==\"sg[0-9]*\", ATTRS{type}==\"3\", ATTRS{vendor}==\"%s\", ATTRS{model}==\"%s\", MODE=\"%s\", GROUP=\"%s\", ENV{libsane_matched}=\"yes\"\n",
+ scsiid->scsi_vendor_id, scsiid->scsi_product_id, DEVMODE, DEVGROUP);
+
+ scsiid = scsiid->next;
+ }
+ printf ("LABEL=\"libsane_scsi_rules_end\"\n");
+
+ if (mode == output_mode_udevacl)
+ printf("\nENV{libsane_matched}==\"yes\", RUN+=\"/bin/setfacl -m g:%s:rw $env{DEVNAME}\"\n", DEVGROUP);
+ else
+ printf ("\nENV{libsane_matched}==\"yes\", MODE=\"664\", GROUP=\"scanner\"\n");
+
+ printf ("\nLABEL=\"libsane_rules_end\"\n");
+}
+
+
+/* print libsane.rules for Linux udev */
+static void
+print_udevhwdb_header (void)
+{
+ time_t current_time = time (0);
+ printf ("# This file was automatically created based on description files (*.desc)\n"
+ "# by sane-desc %s from %s on %s",
+ SANE_DESC_VERSION, PACKAGE_STRING, asctime (localtime (&current_time)));
+
+ printf
+ ("#\n"
+ "# udev rules file for supported USB and SCSI devices\n"
+ "#\n"
+ "# For the list of supported USB devices see /usr/lib/udev/hwdb.d/20-sane.hwdb\n"
+ "#\n"
+ "# The SCSI device support is very basic and includes only\n"
+ "# scanners that mark themselves as type \"scanner\" or\n"
+ "# SCSI-scanners from HP and other vendors that are entitled \"processor\"\n"
+ "# but are treated accordingly.\n"
+ "#\n");
+ printf
+ ("# If your SCSI scanner isn't listed below, you can add it to a new rules\n"
+ "# file under /etc/udev/rules.d/.\n"
+ "#\n"
+ "# If your scanner is supported by some external backend (brother, epkowa,\n"
+ "# hpaio, etc) please ask the author of the backend to provide proper\n"
+ "# device detection support for your OS\n"
+ "#\n"
+ "# If the scanner is supported by sane-backends, please mail the entry to\n"
+ "# the sane-devel mailing list (sane-devel@lists.alioth.debian.org).\n"
+ "#\n"
+ );
+}
+
+static void
+print_udevhwdb (void)
+{
+ scsiid_type *scsiid = create_scsiids_table ();
+ int i;
+
+ print_udevhwdb_header ();
+ printf("ACTION!=\"add\", GOTO=\"libsane_rules_end\"\n\n");
+
+ printf("# The following rule will disable USB autosuspend for the device\n");
+ printf("ENV{DEVTYPE}==\"usb_device\", ENV{libsane_matched}==\"yes\", TEST==\"power/control\", ATTR{power/control}=\"on\"\n\n");
+
+ printf ("SUBSYSTEMS!=\"scsi\", GOTO=\"libsane_rules_end\"\n");
+ printf ("KERNEL!=\"sg[0-9]*\", GOTO=\"libsane_rules_end\"\n\n");
+
+ printf ("# Generic: SCSI device type 6 indicates a scanner\n");
+ printf ("ATTRS{type}==\"6\", ENV{libsane_matched}=\"yes\"\n\n");
+
+ printf ("# Some scanners advertise themselves as SCSI device type 3\n\n");
+
+ printf ("# Wildcard: for some Epson SCSI scanners\n");
+ printf ("ATTRS{type}==\"3\", ATTRS{vendor}==\"EPSON\", ATTRS{model}==\"SCANNER*\", ENV{libsane_matched}=\"yes\"\n\n");
+
+ while (scsiid)
+ {
+ manufacturer_model_type * name = scsiid->name;
+
+ if (!scsiid->is_processor)
+ {
+ scsiid = scsiid->next;
+ continue;
+ }
+
+ /* Wildcard for Epson scanners: vendor = EPSON, product = SCANNER* */
+ if ((strcmp(scsiid->scsi_vendor_id, "EPSON") == 0)
+ && (strncmp(scsiid->scsi_product_id, "SCANNER", 7) == 0))
+ {
+ scsiid = scsiid->next;
+ continue;
+ }
+
+ i = 0;
+ printf ("# ");
+ while (name)
+ {
+ if ((name != scsiid->name) && (i > 0))
+ printf (" | ");
+ printf ("%s", name->name);
+ name = name->next;
+
+ i++;
+
+ /*
+ * Limit the number of model names on the same line to 3,
+ * as udev cannot handle very long lines and prints a warning
+ * message while loading the rules files.
+ */
+ if ((i == 3) && (name != NULL))
+ {
+ printf("\n# ");
+ i = 0;
+ }
+ }
+ printf ("\n");
+
+ printf ("ATTRS{type}==\"3\", ATTRS{vendor}==\"%s\", ATTRS{model}==\"%s\", ENV{libsane_matched}=\"yes\"\n\n",
+ scsiid->scsi_vendor_id, scsiid->scsi_product_id);
+
+ scsiid = scsiid->next;
+ }
+
+ printf ("\nLABEL=\"libsane_rules_end\"\n");
+}
+
+/* print /usr/lib/udev/hwdb.d/20-sane.conf for Linux hwdb */
+static void
+print_hwdb_header (void)
+{
+ time_t current_time = time (0);
+ printf ("# This file was automatically created based on description files (*.desc)\n"
+ "# by sane-desc %s from %s on %s",
+ SANE_DESC_VERSION, PACKAGE_STRING, asctime (localtime (&current_time)));
+
+ printf
+ ("#\n"
+ "# hwdb file for supported USB devices\n"
+ "#\n");
+ printf
+ ("# If your scanner isn't listed below, you can add it to a new hwdb file\n"
+ "# under /etc/udev/hwdb.d/.\n"
+ "#\n"
+ "# If your scanner is supported by some external backend (brother, epkowa,\n"
+ "# hpaio, etc) please ask the author of the backend to provide proper\n"
+ "# device detection support for your OS\n"
+ "#\n"
+ "# If the scanner is supported by sane-backends, please mail the entry to\n"
+ "# the sane-devel mailing list (sane-devel@lists.alioth.debian.org).\n"
+ "#\n"
+ );
+}
+
+static void
+print_hwdb (void)
+{
+ usbid_type *usbid = create_usbids_table ();
+ char *vendor_id;
+ char *product_id;
+ int i,j;
+
+ print_hwdb_header ();
+
+ while (usbid)
+ {
+ manufacturer_model_type * name = usbid->name;
+
+ i = 0;
+ printf ("# ");
+ while (name)
+ {
+ if ((name != usbid->name) && (i > 0))
+ printf (" | ");
+ printf ("%s", name->name);
+ name = name->next;
+
+ i++;
+
+ /*
+ * Limit the number of model names on the same line to 3,
+ * as udev cannot handle very long lines and prints a warning
+ * message while loading the rules files.
+ */
+ if ((i == 3) && (name != NULL))
+ {
+ printf("\n# ");
+ i = 0;
+ }
+ }
+ printf ("\n");
+
+ vendor_id = strdup(usbid->usb_vendor_id + 2);
+ product_id = strdup(usbid->usb_product_id + 2);
+
+ for(j = 0; j < 4; j++) {
+ vendor_id[j] = toupper(vendor_id[j]);
+ product_id[j] = toupper(vendor_id[j]);
+ }
+
+ printf ("usb:v%sp%s*\n libsane_matched=yes\n\n",
+ vendor_id, product_id);
+
+ free(vendor_id);
+ free(product_id);
+
+ usbid = usbid->next;
+ }
+}
+
+static void
+print_plist (void)
+{
+ usbid_type *usbid = create_usbids_table ();
+
+ printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ printf ("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
+ printf ("<plist version=\"1.0\">\n");
+ printf ("<dict>\n");
+ printf ("\t<key>device info version</key>\n");
+ printf ("\t<string>2.0</string>\n");
+ printf ("\t<key>usb</key>\n");
+ printf ("\t<dict>\n");
+ printf ("\t\t<key>IOUSBDevice</key>\n");
+ printf ("\t\t<array>\n");
+ while (usbid)
+ {
+ printf ("\t\t\t<dict>\n");
+ printf ("\t\t\t\t<key>device type</key>\n");
+ printf ("\t\t\t\t<string>scanner</string>\n");
+ printf ("\t\t\t\t<key>product</key>\n");
+ printf ("\t\t\t\t<string>%s</string>\n", usbid->usb_product_id);
+ printf ("\t\t\t\t<key>vendor</key>\n");
+ printf ("\t\t\t\t<string>%s</string>\n", usbid->usb_vendor_id);
+ printf ("\t\t\t</dict>\n");
+ usbid = usbid->next;
+ }
+ printf ("\t\t</array>\n");
+ printf ("\t</dict>\n");
+ printf ("</dict>\n");
+ printf ("</plist>\n");
+}
+
+
+static void
+print_hal (int new)
+{
+ int i;
+ SANE_Bool in_match;
+ char *last_vendor;
+ scsiid_type *scsiid = create_scsiids_table ();
+ usbid_type *usbid = create_usbids_table ();
+
+ printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ printf ("<deviceinfo version=\"0.2\">\n");
+ printf (" <device>\n");
+ printf (" <!-- SCSI-SUBSYSTEM -->\n");
+ printf (" <match key=\"info.category\" string=\"scsi_generic\">\n");
+ printf (" <!-- Some SCSI Scanners announce themselves \"processor\" -->\n");
+ printf (" <match key=\"@info.parent:scsi.type\" string=\"processor\">\n");
+
+ last_vendor = "";
+ in_match = SANE_FALSE;
+ while (scsiid)
+ {
+ manufacturer_model_type * name = scsiid->name;
+
+ if (!scsiid->is_processor)
+ {
+ scsiid = scsiid->next;
+ continue;
+ }
+
+ if (strcmp(last_vendor, scsiid->scsi_vendor_id) != 0)
+ {
+ if (in_match)
+ printf (" </match>\n");
+
+ printf (" <match key=\"@info.parent:scsi.vendor\" string=\"%s\">\n", scsiid->scsi_vendor_id);
+ last_vendor = scsiid->scsi_vendor_id;
+ in_match = SANE_TRUE;
+ }
+
+ printf (" <!-- SCSI Scanner ");
+ while (name)
+ {
+ if (name != scsiid->name)
+ printf (" | ");
+ printf ("\"%s\"", name->name);
+ name = name->next;
+ }
+ printf (" -->\n");
+ printf (" <match key=\"@info.parent:scsi.model\" string=\"%s\">\n", scsiid->scsi_product_id);
+ printf (" <append key=\"info.capabilities\" type=\"strlist\">scanner</append>\n");
+ printf (" </match>\n");
+
+ scsiid = scsiid->next;
+ }
+
+ if (in_match)
+ printf (" </match>\n");
+
+ printf (" </match>\n");
+ printf (" </match>\n");
+ printf (" <!-- USB-SUBSYSTEM -->\n");
+
+ if (new)
+ printf (" <match key=\"info.subsystem\" string=\"usb\">\n");
+ else
+ printf (" <match key=\"info.bus\" string=\"usb\">\n");
+
+ last_vendor = "";
+ in_match = SANE_FALSE;
+ while (usbid)
+ {
+ manufacturer_model_type * name = usbid->name;
+
+ if (strcmp(last_vendor, usbid->usb_vendor_id) != 0)
+ {
+ if (in_match)
+ printf (" </match>\n");
+
+ printf (" <match key=\"usb.vendor_id\" int=\"%s\">\n", usbid->usb_vendor_id);
+ last_vendor = usbid->usb_vendor_id;
+ in_match = SANE_TRUE;
+ }
+
+ i = 0;
+ printf (" <!-- ");
+ while (name)
+ {
+ if ((name != usbid->name) && (i > 0))
+ printf (" | ");
+
+ printf ("%s", name->name);
+ name = name->next;
+ i++;
+
+ if ((i == 3) && (name != NULL))
+ {
+ printf("\n ");
+ i = 0;
+ }
+ }
+ printf (" -->\n");
+ printf (" <match key=\"usb.product_id\" int=\"%s\">\n", usbid->usb_product_id);
+ printf (" <append key=\"info.capabilities\" type=\"strlist\">scanner</append>\n");
+ printf (" <merge key=\"scanner.access_method\" type=\"string\">proprietary</merge>\n");
+ printf (" </match>\n");
+
+ usbid = usbid->next;
+ }
+
+ if (in_match)
+ printf (" </match>\n");
+
+ printf (" </match>\n");
+
+ printf (" </device>\n");
+ printf ("</deviceinfo>\n");
+}
+
+int
+main (int argc, char **argv)
+{
+ program_name = strrchr (argv[0], '/');
+ if (program_name)
+ ++program_name;
+ else
+ program_name = argv[0];
+
+ if (!get_options (argc, argv))
+ return 1;
+ if (!read_files ())
+ return 1;
+ switch (mode)
+ {
+ case output_mode_ascii:
+ ascii_print_backends ();
+ break;
+ case output_mode_xml:
+ xml_print_backends ();
+ break;
+ case output_mode_html_backends_split:
+ html_print_backends_split ();
+ break;
+ case output_mode_html_mfgs:
+ html_print_mfgs ();
+ break;
+ case output_mode_statistics:
+ print_statistics ();
+ break;
+ case output_mode_usermap:
+ print_usermap ();
+ break;
+ case output_mode_db:
+ print_db ();
+ break;
+ case output_mode_udev:
+ case output_mode_udevacl:
+ print_udev ();
+ break;
+ case output_mode_udevhwdb:
+ print_udevhwdb ();
+ break;
+ case output_mode_hwdb:
+ print_hwdb ();
+ break;
+ case output_mode_plist:
+ print_plist ();
+ break;
+ case output_mode_hal:
+ print_hal (0);
+ break;
+ case output_mode_halnew:
+ print_hal (1);
+ break;
+ default:
+ DBG_ERR ("Unknown output mode\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/tools/sane-find-scanner.c b/tools/sane-find-scanner.c
new file mode 100644
index 0000000..dbfd0da
--- /dev/null
+++ b/tools/sane-find-scanner.c
@@ -0,0 +1,2100 @@
+/* sane-find-scanner.c
+
+ Copyright (C) 1997-2013 Oliver Rauch, Henning Meier-Geinitz, and others.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ */
+
+#include "../include/sane/config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+
+#if defined (HAVE_DDK_NTDDSCSI_H) || defined (HAVE_NTDDSCSI_H)
+# define WIN32_SCSI
+# include <windows.h>
+# if defined (HAVE_DDK_NTDDSCSI_H)
+# include <ddk/scsi.h>
+# include <ddk/ntddscsi.h>
+# elif defined (HAVE_NTDDSCSI_H)
+# include <ntddscsi.h>
+# endif
+#endif
+
+#include "../include/sane/sanei.h"
+#include "../include/sane/sanei_scsi.h"
+#include "../include/sane/sanei_pa4s2.h"
+#include "../include/sane/sanei_config.h"
+
+#ifdef HAVE_LIBUSB
+#ifdef HAVE_LUSB0_USB_H
+#include <lusb0_usb.h>
+#else
+#include <usb.h>
+#endif
+extern char * check_usb_chip (struct usb_device *dev, int verbosity, SANE_Bool from_file);
+#endif
+
+#ifdef HAVE_LIBUSB_1_0
+#include <libusb.h>
+extern char * check_usb_chip (int verbosity,
+ struct libusb_device_descriptor desc,
+ libusb_device_handle *hdl,
+ struct libusb_config_descriptor *config0);
+#endif
+
+#include "../include/sane/sanei_usb.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+static const char *prog_name;
+static int verbose = 1;
+static SANE_Bool force = SANE_FALSE;
+static SANE_Bool device_found = SANE_FALSE;
+static SANE_Bool libusb_device_found = SANE_FALSE;
+static SANE_Bool unknown_found = SANE_FALSE;
+
+#ifdef HAVE_LIBUSB_1_0
+libusb_context *sfs_usb_ctx;
+#endif
+
+typedef struct
+{
+ unsigned char *cmd;
+ size_t size;
+}
+scsiblk;
+
+#define INQUIRY 0x12
+#define set_inquiry_return_size(icb,val) icb[0x04]=val
+#define IN_periph_devtype_cpu 0x03
+#define IN_periph_devtype_scanner 0x06
+#define get_scsi_inquiry_vendor(in, buf) strncpy(buf, in + 0x08, 0x08)
+#define get_scsi_inquiry_product(in, buf) strncpy(buf, in + 0x10, 0x010)
+#define get_scsi_inquiry_version(in, buf) strncpy(buf, in + 0x20, 0x04)
+#define get_scsi_inquiry_periph_devtype(in) (in[0] & 0x1f)
+#define get_scsi_inquiry_additional_length(in) in[0x04]
+#define set_scsi_inquiry_length(out,n) out[0x04]=n-5
+
+static unsigned char inquiryC[] = {
+ INQUIRY, 0x00, 0x00, 0x00, 0xff, 0x00
+};
+static scsiblk inquiry = {
+ inquiryC, sizeof (inquiryC)
+};
+
+static void
+usage (char *msg)
+{
+ fprintf (stderr, "Usage: %s [-hvqf] [devname ...]\n", prog_name);
+ fprintf (stderr, "\t-h: print this help message\n");
+ fprintf (stderr, "\t-v: be more verbose (can be used multiple times)\n");
+ fprintf (stderr, "\t-q: be quiet (print only devices, no comments)\n");
+ fprintf (stderr, "\t-f: force opening devname as SCSI even if it looks "
+ "like USB\n");
+ fprintf (stderr, "\t-p: enable scanning for parallel port devices\n");
+#ifdef HAVE_LIBUSB
+ fprintf (stderr, "\t-F file: try to detect chipset from given "
+ "/proc/bus/usb/devices file\n");
+#endif
+ if (msg)
+ fprintf (stderr, "\t%s\n", msg);
+}
+
+/* if SCSI generic is optional on your OS, and there is a software test
+ which will determine if it is included, add it here. If you are sure
+ that SCSI generic was found, return 1. If SCSI generic is always
+ available in your OS, return 1 */
+
+static int
+check_sg (void)
+{
+#if defined(__linux__)
+ /* Assumption: /proc/devices lines are shorter than 256 characters */
+ char line[256], driver[256] = "";
+ FILE *stream;
+
+ stream = fopen ("/proc/devices", "r");
+ /* Likely reason for failure, no /proc => probably no SG either */
+ if (stream == NULL)
+ return 0;
+
+ while (fgets (line, sizeof (line) - 1, stream))
+ {
+ if (sscanf (line, " %*d %s\n", driver) > 0 && !strcmp (driver, "sg"))
+ break;
+ }
+ fclose (stream);
+
+ if (strcmp (driver, "sg"))
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+#endif
+ return 1; /* Give up, and assume yes to avoid false negatives */
+}
+
+/* Display a buffer in the log. Display by lines of 16 bytes. */
+static void
+hexdump (const char *comment, unsigned char *buf, const int length)
+{
+ int i;
+ char line[128];
+ char *ptr;
+ char asc_buf[17];
+ char *asc_ptr;
+
+ printf (" %s\n", comment);
+
+ i = 0;
+ goto start;
+
+ do
+ {
+ if (i < length)
+ {
+ ptr += sprintf (ptr, " %2.2x", *buf);
+
+ if (*buf >= 32 && *buf <= 127)
+ {
+ asc_ptr += sprintf (asc_ptr, "%c", *buf);
+ }
+ else
+ {
+ asc_ptr += sprintf (asc_ptr, ".");
+ }
+ }
+ else
+ {
+ /* After the length; do nothing. */
+ ptr += sprintf (ptr, " ");
+ }
+
+ i++;
+ buf++;
+
+ if ((i % 16) == 0)
+ {
+ /* It's a new line */
+ printf (" %s %s\n", line, asc_buf);
+
+ start:
+ ptr = line;
+ *ptr = '\0';
+ asc_ptr = asc_buf;
+ *asc_ptr = '\0';
+
+ ptr += sprintf (ptr, " %3.3d:", i);
+ }
+
+ }
+ while (i < ((length + 15) & ~15));
+}
+
+static SANE_Status
+scanner_do_scsi_inquiry (unsigned char *buffer, int sfd)
+{
+ size_t size;
+ SANE_Status status;
+
+ memset (buffer, '\0', 256); /* clear buffer */
+
+ size = 5; /* first get only 5 bytes to get size of
+ inquiry_return_block */
+ set_inquiry_return_size (inquiry.cmd, size);
+ status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
+
+ if (status != SANE_STATUS_GOOD)
+ return (status);
+
+ size = get_scsi_inquiry_additional_length (buffer) + 5;
+
+ /* then get inquiry with actual size */
+ set_inquiry_return_size (inquiry.cmd, size);
+ status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
+
+ return (status);
+}
+
+static void
+scanner_identify_scsi_scanner (unsigned char *buffer, int sfd,
+ char *devicename)
+{
+ unsigned char vendor[9];
+ unsigned char product[17];
+ unsigned char version[5];
+ unsigned char *pp;
+ unsigned int devtype;
+ SANE_Status status;
+ static char *devtypes[] = {
+ "disk", "tape", "printer", "processor", "CD-writer",
+ "CD-drive", "scanner", "optical-drive", "jukebox",
+ "communicator"
+ };
+ status = scanner_do_scsi_inquiry (buffer, sfd);
+ if (status != SANE_STATUS_GOOD)
+ {
+ if (verbose > 1)
+ printf ("inquiry for device %s failed (%s)\n",
+ devicename, sane_strstatus (status));
+ return;
+ }
+
+ if (verbose > 2)
+ hexdump ("Inquiry for device:", buffer,
+ get_scsi_inquiry_additional_length (buffer) + 5);
+
+ devtype = get_scsi_inquiry_periph_devtype (buffer);
+ if (verbose <= 1 && devtype != IN_periph_devtype_scanner
+ /* old HP scanners use the CPU id ... */
+ && devtype != IN_periph_devtype_cpu)
+ return; /* no, continue searching */
+
+ get_scsi_inquiry_vendor ((char *) buffer, (char *) vendor);
+ get_scsi_inquiry_product ((char *) buffer, (char *) product);
+ get_scsi_inquiry_version ((char *) buffer, (char *) version);
+
+ pp = &vendor[7];
+ vendor[8] = '\0';
+ while (pp >= vendor && (*pp == ' ' || *pp >= 127))
+ *pp-- = '\0';
+
+ pp = &product[15];
+ product[16] = '\0';
+ while (pp >= product && (*pp == ' ' || *pp >= 127))
+ *pp-- = '\0';
+
+ pp = &version[3];
+ version[4] = '\0';
+ while (pp >= version && (*pp == ' ' || *(pp - 1) >= 127))
+ *pp-- = '\0';
+
+ device_found = SANE_TRUE;
+ printf ("found SCSI %s \"%s %s %s\" at %s\n",
+ devtype < NELEMS (devtypes) ? devtypes[devtype] : "unknown device",
+ vendor, product, version, devicename);
+ return;
+}
+
+static void
+check_scsi_file (char *file_name)
+{
+ int result;
+ int sfd;
+ unsigned char buffer[16384];
+
+ if (strstr (file_name, "usb")
+ || strstr (file_name, "uscanner") || strstr (file_name, "ugen"))
+ {
+ if (force)
+ {
+ if (verbose > 1)
+ printf ("checking %s even though it looks like a USB device...",
+ file_name);
+ }
+ else
+ {
+ if (verbose > 1)
+ printf ("ignored %s (not a SCSI device)\n", file_name);
+ return;
+ }
+ }
+ else if (verbose > 1)
+ printf ("checking %s...", file_name);
+
+ result = sanei_scsi_open (file_name, &sfd, NULL, NULL);
+
+ if (verbose > 1)
+ {
+ if (result != 0)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ else
+ printf (" open ok\n");
+ }
+
+ if (result == SANE_STATUS_GOOD)
+ {
+ scanner_identify_scsi_scanner (buffer, sfd, file_name);
+ sanei_scsi_close (sfd);
+ }
+ return;
+}
+
+static void
+check_usb_file (char *file_name)
+{
+ SANE_Status result;
+ SANE_Word vendor, product;
+ SANE_Int fd;
+
+ if (!strstr (file_name, "usb")
+ && !strstr (file_name, "uscanner") && !strstr (file_name, "ugen"))
+ {
+ if (force)
+ {
+ if (verbose > 1)
+ printf ("checking %s even though doesn't look like a "
+ "USB device...", file_name);
+ }
+ else
+ {
+ if (verbose > 1)
+ printf ("ignored %s (not a USB device)\n", file_name);
+ return;
+ }
+ }
+ else if (verbose > 1)
+ printf ("checking %s...", file_name);
+
+ result = sanei_usb_open (file_name, &fd);
+
+ if (result != SANE_STATUS_GOOD)
+ {
+ if (verbose > 1)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ }
+ else
+ {
+ result = sanei_usb_get_vendor_product (fd, &vendor, &product);
+ if (result == SANE_STATUS_GOOD)
+ {
+ if (verbose > 1)
+ printf (" open ok, vendor and product ids were identified\n");
+ printf ("found USB scanner (vendor=0x%04x, "
+ "product=0x%04x) at %s\n", vendor, product, file_name);
+ }
+ else
+ {
+ if (verbose > 1)
+ printf (" open ok, but vendor and product could NOT be "
+ "identified\n");
+ printf ("found USB scanner (UNKNOWN vendor and product) "
+ "at device %s\n", file_name);
+ unknown_found = SANE_TRUE;
+ }
+ device_found = SANE_TRUE;
+ sanei_usb_close (fd);
+ }
+}
+
+#ifdef HAVE_LIBUSB
+
+static char *
+get_libusb_string_descriptor (struct usb_device *dev, int index)
+{
+ usb_dev_handle *handle;
+ char *buffer, short_buffer[2];
+ struct usb_string_descriptor *sd;
+ int size = 2;
+ int i;
+
+ if (!index)
+ return 0;
+
+ handle = usb_open (dev);
+ if (!handle)
+ return 0;
+
+ sd = (struct usb_string_descriptor *) short_buffer;
+
+ if (usb_control_msg (handle,
+ USB_ENDPOINT_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE,
+ USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) + index, 0, short_buffer,
+ size, 1000) < 0)
+ {
+ usb_close (handle);
+ return 0;
+ }
+
+ if (sd->bLength < 2
+ || sd->bDescriptorType != USB_DT_STRING)
+ {
+ usb_close (handle);
+ return 0;
+ }
+
+ size = sd->bLength;
+
+ buffer = calloc (1, size + 1);
+ if (!buffer)
+ return 0;
+
+ sd = (struct usb_string_descriptor *) buffer;
+
+ if (usb_control_msg (handle,
+ USB_ENDPOINT_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE,
+ USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) + index, 0, buffer,
+ size, 1000) < 0)
+ {
+ usb_close (handle);
+ free (buffer);
+ return 0;
+ }
+
+ if (sd->bLength < 2 || sd->bLength > size
+ || sd->bDescriptorType != USB_DT_STRING)
+ {
+ usb_close (handle);
+ free (buffer);
+ return 0;
+ }
+ size = sd->bLength - 2;
+ for (i = 0; i < (size / 2); i++)
+ buffer[i] = buffer[2 + 2 * i];
+ buffer[i] = 0;
+
+ usb_close (handle);
+ return buffer;
+}
+
+static char *
+get_libusb_vendor (struct usb_device *dev)
+{
+ return get_libusb_string_descriptor (dev, dev->descriptor.iManufacturer);
+}
+
+static char *
+get_libusb_product (struct usb_device *dev)
+{
+ return get_libusb_string_descriptor (dev, dev->descriptor.iProduct);
+}
+
+static void
+check_libusb_device (struct usb_device *dev, SANE_Bool from_file)
+{
+ int is_scanner = 0;
+ char *vendor;
+ char *product;
+ int interface_nr;
+
+ if (!dev->config)
+ {
+ if (verbose > 1)
+ printf ("device 0x%04x/0x%04x is not configured\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ return;
+ }
+
+ vendor = get_libusb_vendor (dev);
+ product = get_libusb_product (dev);
+
+ if (verbose > 2)
+ {
+ /* print everything we know about the device */
+ char *buf;
+ int config_nr;
+ struct usb_device_descriptor *d = &dev->descriptor;
+
+ printf ("\n");
+ printf ("<device descriptor of 0x%04x/0x%04x at %s:%s",
+ d->idVendor, d->idProduct, dev->bus->dirname, dev->filename);
+ if (vendor || product)
+ {
+ printf (" (%s%s%s)", vendor ? vendor : "",
+ (vendor && product) ? " " : "", product ? product : "");
+ }
+ printf (">\n");
+ printf ("bLength %d\n", d->bLength);
+ printf ("bDescriptorType %d\n", d->bDescriptorType);
+ printf ("bcdUSB %d.%d%d\n", d->bcdUSB >> 8,
+ (d->bcdUSB >> 4) & 15, d->bcdUSB & 15);
+ printf ("bDeviceClass %d\n", d->bDeviceClass);
+ printf ("bDeviceSubClass %d\n", d->bDeviceSubClass);
+ printf ("bDeviceProtocol %d\n", d->bDeviceProtocol);
+ printf ("bMaxPacketSize0 %d\n", d->bMaxPacketSize0);
+ printf ("idVendor 0x%04X\n", d->idVendor);
+ printf ("idProduct 0x%04X\n", d->idProduct);
+ printf ("bcdDevice %d.%d%d\n", d->bcdDevice >> 8,
+ (d->bcdDevice >> 4) & 15, d->bcdDevice & 15);
+ printf ("iManufacturer %d (%s)\n", d->iManufacturer,
+ (vendor) ? vendor : "");
+ printf ("iProduct %d (%s)\n", d->iProduct,
+ (product) ? product : "");
+
+ buf = get_libusb_string_descriptor (dev, d->iSerialNumber);
+ printf ("iSerialNumber %d (%s)\n", d->iSerialNumber,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+ printf ("bNumConfigurations %d\n", d->bNumConfigurations);
+
+ for (config_nr = 0; config_nr < d->bNumConfigurations; config_nr++)
+ {
+ struct usb_config_descriptor *c = &dev->config[config_nr];
+ int interface_nr;
+
+ printf (" <configuration %d>\n", config_nr);
+ printf (" bLength %d\n", c->bLength);
+ printf (" bDescriptorType %d\n", c->bDescriptorType);
+ printf (" wTotalLength %d\n", c->wTotalLength);
+ printf (" bNumInterfaces %d\n", c->bNumInterfaces);
+ printf (" bConfigurationValue %d\n", c->bConfigurationValue);
+ buf = get_libusb_string_descriptor (dev, c->iConfiguration);
+ printf (" iConfiguration %d (%s)\n", c->iConfiguration,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+ printf (" bmAttributes %d (%s%s)\n", c->bmAttributes,
+ c->bmAttributes & 64 ? "Self-powered" : "",
+ c->bmAttributes & 32 ? "Remote Wakeup" : "");
+ printf (" MaxPower %d mA\n", c->MaxPower * 2);
+
+ for (interface_nr = 0; interface_nr < c->bNumInterfaces;
+ interface_nr++)
+ {
+ struct usb_interface *interface = &c->interface[interface_nr];
+ int alt_setting_nr;
+
+ printf (" <interface %d>\n", interface_nr);
+ for (alt_setting_nr = 0;
+ alt_setting_nr < interface->num_altsetting;
+ alt_setting_nr++)
+ {
+ struct usb_interface_descriptor *i
+ = &interface->altsetting[alt_setting_nr];
+ int ep_nr;
+ printf (" <altsetting %d>\n", alt_setting_nr);
+ printf (" bLength %d\n", i->bLength);
+ printf (" bDescriptorType %d\n", i->bDescriptorType);
+ printf (" bInterfaceNumber %d\n", i->bInterfaceNumber);
+ printf (" bAlternateSetting %d\n", i->bAlternateSetting);
+ printf (" bNumEndpoints %d\n", i->bNumEndpoints);
+ printf (" bInterfaceClass %d\n", i->bInterfaceClass);
+ printf (" bInterfaceSubClass %d\n",
+ i->bInterfaceSubClass);
+ printf (" bInterfaceProtocol %d\n",
+ i->bInterfaceProtocol);
+ buf = get_libusb_string_descriptor (dev, i->iInterface);
+ printf (" iInterface %d (%s)\n", i->iInterface,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+
+ for (ep_nr = 0; ep_nr < i->bNumEndpoints; ep_nr++)
+ {
+ struct usb_endpoint_descriptor *e = &i->endpoint[ep_nr];
+ char *ep_type;
+
+ switch (e->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+ {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ ep_type = "control";
+ break;
+ case USB_ENDPOINT_TYPE_ISOCHRONOUS:
+ ep_type = "isochronous";
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ ep_type = "bulk";
+ break;
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ ep_type = "interrupt";
+ break;
+ default:
+ ep_type = "unknown";
+ break;
+ }
+ printf (" <endpoint %d>\n", ep_nr);
+ printf (" bLength %d\n", e->bLength);
+ printf (" bDescriptorType %d\n",
+ e->bDescriptorType);
+ printf (" bEndpointAddress 0x%02X (%s 0x%02X)\n",
+ e->bEndpointAddress,
+ e->bEndpointAddress & USB_ENDPOINT_DIR_MASK ?
+ "in" : "out",
+ e->
+ bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
+ printf (" bmAttributes %d (%s)\n",
+ e->bmAttributes, ep_type);
+ printf (" wMaxPacketSize %d\n",
+ e->wMaxPacketSize);
+ printf (" bInterval %d ms\n", e->bInterval);
+ printf (" bRefresh %d\n", e->bRefresh);
+ printf (" bSynchAddress %d\n", e->bSynchAddress);
+ }
+ }
+ }
+ }
+
+ }
+
+ /* Some heuristics, which device may be a scanner */
+ if (dev->descriptor.idVendor == 0) /* hub */
+ --is_scanner;
+ if (dev->descriptor.idProduct == 0) /* hub */
+ --is_scanner;
+
+ for (interface_nr = 0; interface_nr < dev->config[0].bNumInterfaces && is_scanner <= 0; interface_nr++)
+ {
+ switch (dev->descriptor.bDeviceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ ++is_scanner;
+ break;
+ case USB_CLASS_PER_INTERFACE:
+ if (dev->config[0].interface[interface_nr].num_altsetting == 0 ||
+ !dev->config[0].interface[interface_nr].altsetting)
+ break;
+ switch (dev->config[0].interface[interface_nr].altsetting[0].bInterfaceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ case USB_CLASS_PER_INTERFACE:
+ case 16: /* data? */
+ ++is_scanner;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (is_scanner > 0)
+ {
+ char * chipset = check_usb_chip (dev, verbose, from_file);
+
+ printf ("found USB scanner (vendor=0x%04x", dev->descriptor.idVendor);
+ if (vendor)
+ printf (" [%s]", vendor);
+ printf (", product=0x%04x", dev->descriptor.idProduct);
+ if (product)
+ printf (" [%s]", product);
+ if (chipset)
+ printf (", chip=%s", chipset);
+ if (from_file)
+ printf (")\n");
+ else
+ printf (") at libusb:%s:%s\n", dev->bus->dirname, dev->filename);
+
+ libusb_device_found = SANE_TRUE;
+ device_found = SANE_TRUE;
+ }
+
+ if (vendor)
+ free (vendor);
+
+ if (product)
+ free (product);
+}
+#endif /* HAVE_LIBUSB */
+
+
+#ifdef HAVE_LIBUSB_1_0
+static char *
+sfs_libusb_strerror (int errcode)
+{
+ /* Error codes & descriptions from the libusb-1.0 documentation */
+
+ switch (errcode)
+ {
+ case LIBUSB_SUCCESS:
+ return "Success (no error)";
+
+ case LIBUSB_ERROR_IO:
+ return "Input/output error";
+
+ case LIBUSB_ERROR_INVALID_PARAM:
+ return "Invalid parameter";
+
+ case LIBUSB_ERROR_ACCESS:
+ return "Access denied (insufficient permissions)";
+
+ case LIBUSB_ERROR_NO_DEVICE:
+ return "No such device (it may have been disconnected)";
+
+ case LIBUSB_ERROR_NOT_FOUND:
+ return "Entity not found";
+
+ case LIBUSB_ERROR_BUSY:
+ return "Resource busy";
+
+ case LIBUSB_ERROR_TIMEOUT:
+ return "Operation timed out";
+
+ case LIBUSB_ERROR_OVERFLOW:
+ return "Overflow";
+
+ case LIBUSB_ERROR_PIPE:
+ return "Pipe error";
+
+ case LIBUSB_ERROR_INTERRUPTED:
+ return "System call interrupted (perhaps due to signal)";
+
+ case LIBUSB_ERROR_NO_MEM:
+ return "Insufficient memory";
+
+ case LIBUSB_ERROR_NOT_SUPPORTED:
+ return "Operation not supported or unimplemented on this platform";
+
+ case LIBUSB_ERROR_OTHER:
+ return "Other error";
+
+ default:
+ return "Unknown libusb-1.0 error code";
+ }
+
+ return "Unknown libusb-1.0 error code";
+}
+
+static char *
+get_libusb_string_descriptor (libusb_device_handle *hdl, int index)
+{
+ unsigned char *buffer, short_buffer[2];
+ int size;
+ int ret;
+ int i;
+
+ if (!index)
+ return NULL;
+
+ ret = libusb_get_descriptor (hdl, LIBUSB_DT_STRING, index,
+ short_buffer, sizeof (short_buffer));
+ if (ret < 0)
+ {
+ printf ("could not fetch string descriptor: %s\n",
+ sfs_libusb_strerror (ret));
+ return NULL;
+ }
+
+ if ((short_buffer[0] < 2) /* descriptor length */
+ || (short_buffer[1] != LIBUSB_DT_STRING)) /* descriptor type */
+ return NULL;
+
+ size = short_buffer[0];
+
+ buffer = calloc (1, size + 1);
+ if (!buffer)
+ return NULL;
+
+ ret = libusb_get_descriptor (hdl, LIBUSB_DT_STRING, index,
+ buffer, size);
+ if (ret < 0)
+ {
+ printf ("could not fetch string descriptor (again): %s\n",
+ sfs_libusb_strerror (ret));
+ free (buffer);
+ return NULL;
+ }
+
+ if ((buffer[0] < 2) || (buffer[0] > size) /* descriptor length */
+ || (buffer[1] != LIBUSB_DT_STRING)) /* descriptor type */
+ {
+ free (buffer);
+ return NULL;
+ }
+
+ size = buffer[0] - 2;
+ for (i = 0; i < (size / 2); i++)
+ buffer[i] = buffer[2 + 2 * i];
+ buffer[i] = '\0';
+
+ return (char *) buffer;
+}
+
+static void
+check_libusb_device (libusb_device *dev, SANE_Bool from_file)
+{
+ libusb_device_handle *hdl;
+ struct libusb_device_descriptor desc;
+ struct libusb_config_descriptor *config0;
+
+ int is_scanner = 0;
+ char *vendor;
+ char *product;
+ unsigned short vid, pid;
+ unsigned char busno, address;
+ int config;
+ int intf;
+ int ret;
+
+ busno = libusb_get_bus_number (dev);
+ address = libusb_get_device_address (dev);
+
+ ret = libusb_get_device_descriptor (dev, &desc);
+ if (ret < 0)
+ {
+ printf ("could not get device descriptor for device at %03d:%03d: %s\n",
+ busno, address, sfs_libusb_strerror (ret));
+ return;
+ }
+
+ vid = desc.idVendor;
+ pid = desc.idProduct;
+
+ ret = libusb_open (dev, &hdl);
+ if (ret < 0)
+ {
+ printf ("could not open USB device 0x%04x/0x%04x at %03d:%03d: %s\n",
+ vid, pid, busno, address, sfs_libusb_strerror (ret));
+ return;
+ }
+
+ ret = libusb_get_configuration (hdl, &config);
+ if (ret < 0)
+ {
+ printf ("could not get configuration for device 0x%04x/0x%04x at %03d:%03d: %s\n",
+ vid, pid, busno, address, sfs_libusb_strerror (ret));
+ libusb_close (hdl);
+ return;
+ }
+
+ if (config == 0)
+ {
+ if (verbose > 1)
+ printf ("device 0x%04x/0x%04x at %03d:%03d is not configured\n",
+ vid, pid, busno, address);
+ libusb_close (hdl);
+ return;
+ }
+
+ vendor = get_libusb_string_descriptor (hdl, desc.iManufacturer);
+ product = get_libusb_string_descriptor (hdl, desc.iProduct);
+
+ if (verbose > 2)
+ {
+ /* print everything we know about the device */
+ char *buf;
+ int config_nr;
+
+ printf ("\n");
+ printf ("<device descriptor of 0x%04x/0x%04x at %03d:%03d",
+ vid, pid, busno, address);
+ if (vendor || product)
+ {
+ printf (" (%s%s%s)", (vendor) ? vendor : "",
+ (vendor && product) ? " " : "", (product) ? product : "");
+ }
+ printf (">\n");
+ printf ("bLength %d\n", desc.bLength);
+ printf ("bDescriptorType %d\n", desc.bDescriptorType);
+ printf ("bcdUSB %d.%d%d\n", desc.bcdUSB >> 8,
+ (desc.bcdUSB >> 4) & 15, desc.bcdUSB & 15);
+ printf ("bDeviceClass %d\n", desc.bDeviceClass);
+ printf ("bDeviceSubClass %d\n", desc.bDeviceSubClass);
+ printf ("bDeviceProtocol %d\n", desc.bDeviceProtocol);
+ printf ("bMaxPacketSize0 %d\n", desc.bMaxPacketSize0);
+ printf ("idVendor 0x%04X\n", desc.idVendor);
+ printf ("idProduct 0x%04X\n", desc.idProduct);
+ printf ("bcdDevice %d.%d%d\n", desc.bcdDevice >> 8,
+ (desc.bcdDevice >> 4) & 15, desc.bcdDevice & 15);
+ printf ("iManufacturer %d (%s)\n", desc.iManufacturer,
+ (vendor) ? vendor : "");
+ printf ("iProduct %d (%s)\n", desc.iProduct,
+ (product) ? product : "");
+ buf = get_libusb_string_descriptor (hdl, desc.iSerialNumber);
+ printf ("iSerialNumber %d (%s)\n", desc.iSerialNumber,
+ (buf) ? buf : "");
+ if (buf)
+ free (buf);
+ printf ("bNumConfigurations %d\n", desc.bNumConfigurations);
+
+ for (config_nr = 0; config_nr < desc.bNumConfigurations; config_nr++)
+ {
+ struct libusb_config_descriptor *c;
+
+ ret = libusb_get_config_descriptor (dev, config_nr, &c);
+ if (ret < 0)
+ {
+ printf ("could not get configuration descriptor %d: %s\n",
+ config_nr, sfs_libusb_strerror (ret));
+ continue;
+ }
+
+ printf (" <configuration %d>\n", config_nr);
+ printf (" bLength %d\n", c->bLength);
+ printf (" bDescriptorType %d\n", c->bDescriptorType);
+ printf (" wTotalLength %d\n", c->wTotalLength);
+ printf (" bNumInterfaces %d\n", c->bNumInterfaces);
+ printf (" bConfigurationValue %d\n", c->bConfigurationValue);
+
+ buf = get_libusb_string_descriptor (hdl, c->iConfiguration);
+ printf (" iConfiguration %d (%s)\n", c->iConfiguration,
+ (buf) ? buf : "");
+ free (buf);
+
+ printf (" bmAttributes %d (%s%s)\n", c->bmAttributes,
+ c->bmAttributes & 64 ? "Self-powered" : "",
+ c->bmAttributes & 32 ? "Remote Wakeup" : "");
+ printf (" MaxPower %d mA\n", c->MaxPower * 2);
+
+ for (intf = 0; intf < c->bNumInterfaces; intf++)
+ {
+ const struct libusb_interface *interface;
+ int alt_setting_nr;
+
+ interface = &c->interface[intf];
+
+ printf (" <interface %d>\n", intf);
+ for (alt_setting_nr = 0;
+ alt_setting_nr < interface->num_altsetting;
+ alt_setting_nr++)
+ {
+ const struct libusb_interface_descriptor *i;
+ int ep_nr;
+
+ i = &interface->altsetting[alt_setting_nr];
+
+ printf (" <altsetting %d>\n", alt_setting_nr);
+ printf (" bLength %d\n", i->bLength);
+ printf (" bDescriptorType %d\n", i->bDescriptorType);
+ printf (" bInterfaceNumber %d\n", i->bInterfaceNumber);
+ printf (" bAlternateSetting %d\n", i->bAlternateSetting);
+ printf (" bNumEndpoints %d\n", i->bNumEndpoints);
+ printf (" bInterfaceClass %d\n", i->bInterfaceClass);
+ printf (" bInterfaceSubClass %d\n",
+ i->bInterfaceSubClass);
+ printf (" bInterfaceProtocol %d\n",
+ i->bInterfaceProtocol);
+
+ buf = NULL;
+ buf = get_libusb_string_descriptor (hdl, i->iInterface);
+ printf (" iInterface %d (%s)\n", i->iInterface,
+ (buf) ? buf : "");
+ free (buf);
+ for (ep_nr = 0; ep_nr < i->bNumEndpoints; ep_nr++)
+ {
+ const struct libusb_endpoint_descriptor *e;
+ char *ep_type;
+
+ e = &i->endpoint[ep_nr];
+
+ switch (e->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+ {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ ep_type = "control";
+ break;
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ ep_type = "isochronous";
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ ep_type = "bulk";
+ break;
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ ep_type = "interrupt";
+ break;
+ default:
+ ep_type = "unknown";
+ break;
+ }
+ printf (" <endpoint %d>\n", ep_nr);
+ printf (" bLength %d\n", e->bLength);
+ printf (" bDescriptorType %d\n",
+ e->bDescriptorType);
+ printf (" bEndpointAddress 0x%02X (%s 0x%02X)\n",
+ e->bEndpointAddress,
+ e->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK ?
+ "in" : "out",
+ e->
+ bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
+ printf (" bmAttributes %d (%s)\n",
+ e->bmAttributes, ep_type);
+ printf (" wMaxPacketSize %d\n",
+ e->wMaxPacketSize);
+ printf (" bInterval %d ms\n", e->bInterval);
+ printf (" bRefresh %d\n", e->bRefresh);
+ printf (" bSynchAddress %d\n", e->bSynchAddress);
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Some heuristics, which device may be a scanner */
+ if (desc.idVendor == 0) /* hub */
+ --is_scanner;
+ if (desc.idProduct == 0) /* hub */
+ --is_scanner;
+
+ ret = libusb_get_config_descriptor (dev, 0, &config0);
+ if (ret < 0)
+ {
+ printf ("could not get config[0] descriptor: %s\n",
+ sfs_libusb_strerror (ret));
+
+ goto out_free;
+ }
+
+ for (intf = 0; (intf < config0->bNumInterfaces) && (is_scanner <= 0); intf++)
+ {
+ switch (desc.bDeviceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ ++is_scanner;
+ break;
+ case USB_CLASS_PER_INTERFACE:
+ if ((config0->interface[intf].num_altsetting == 0)
+ || !config0->interface[intf].altsetting)
+ break;
+ switch (config0->interface[intf].altsetting[0].bInterfaceClass)
+ {
+ case USB_CLASS_VENDOR_SPEC:
+ case USB_CLASS_PER_INTERFACE:
+ case 16: /* data? */
+ ++is_scanner;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (is_scanner > 0)
+ {
+ char *chipset = NULL;
+
+ if(!from_file)
+ chipset = check_usb_chip (verbose, desc, hdl, config0);
+
+ printf ("found USB scanner (vendor=0x%04x", vid);
+ if (vendor)
+ printf (" [%s]", vendor);
+ printf (", product=0x%04x", pid);
+ if (product)
+ printf (" [%s]", product);
+ if (chipset)
+ printf (", chip=%s", chipset);
+ if (from_file)
+ printf (")\n");
+ else
+ printf (") at libusb:%03d:%03d\n", busno, address);
+
+ libusb_device_found = SANE_TRUE;
+ device_found = SANE_TRUE;
+ }
+
+ libusb_free_config_descriptor (config0);
+
+ out_free:
+ libusb_close (hdl);
+ if (vendor)
+ free (vendor);
+
+ if (product)
+ free (product);
+}
+#endif /* HAVE_LIBUSB_1_0 */
+
+
+static DIR *
+scan_directory (char *dir_name)
+{
+ struct stat stat_buf;
+ DIR *dir;
+
+ if (verbose > 2)
+ printf ("scanning directory %s\n", dir_name);
+
+ if (stat (dir_name, &stat_buf) < 0)
+ {
+ if (verbose > 1)
+ printf ("cannot stat `%s' (%s)\n", dir_name, strerror (errno));
+ return 0;
+ }
+ if (!S_ISDIR (stat_buf.st_mode))
+ {
+ if (verbose > 1)
+ printf ("`%s' is not a directory\n", dir_name);
+ return 0;
+ }
+ if ((dir = opendir (dir_name)) == 0)
+ {
+ if (verbose > 1)
+ printf ("cannot read directory `%s' (%s)\n", dir_name,
+ strerror (errno));
+ return 0;
+ }
+ return dir;
+}
+
+static char *
+get_next_file (char *dir_name, DIR * dir)
+{
+ struct dirent *dir_entry;
+ static char file_name[PATH_MAX];
+
+ do
+ {
+ dir_entry = readdir (dir);
+ if (!dir_entry)
+ return 0;
+ }
+ while (strcmp (dir_entry->d_name, ".") == 0
+ || strcmp (dir_entry->d_name, "..") == 0);
+
+ if (strlen (dir_name) + strlen (dir_entry->d_name) + 1 > PATH_MAX)
+ {
+ if (verbose > 1)
+ printf ("filename too long\n");
+ return 0;
+ }
+ sprintf (file_name, "%s%s", dir_name, dir_entry->d_name);
+ return file_name;
+}
+
+#if defined(WIN32_SCSI)
+/* Return a list of potential scanners. There's a lot of hardcoded values here that might break on a system with lots of scsi devices. */
+static char **build_scsi_dev_list(void)
+{
+ char **dev_list;
+ int dev_list_index;
+ int hca;
+ HANDLE fd;
+ char scsi_hca_name[20];
+ char buffer[4096];
+ DWORD BytesReturned;
+ BOOL ret;
+ size_t dev_list_size;
+ PSCSI_ADAPTER_BUS_INFO adapter;
+ PSCSI_INQUIRY_DATA inquiry;
+ int i;
+
+ /* Allocate room for about 100 scanners. That should be enough. */
+ dev_list_size = 100;
+ dev_list_index = 0;
+ dev_list = calloc(1, dev_list_size * sizeof(char *));
+
+ hca = 0;
+
+ for(hca = 0; ; hca++) {
+
+ /* Open the adapter */
+ snprintf(scsi_hca_name, 20, "\\\\.\\Scsi%d:", hca);
+ fd = CreateFile(scsi_hca_name, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_RANDOM_ACCESS, NULL );
+
+ if (fd == INVALID_HANDLE_VALUE) {
+ /* Assume there is no more adapter. This is wrong in the case
+ * of hot-plug stuff, but I have yet to see it on a user
+ * machine. */
+ break;
+ }
+
+ /* Get the inquiry info for the devices on that hca. */
+ ret = DeviceIoControl(fd,
+ IOCTL_SCSI_GET_INQUIRY_DATA,
+ NULL,
+ 0,
+ buffer,
+ sizeof(buffer),
+ &BytesReturned,
+ FALSE);
+
+ if(ret == 0)
+ {
+ CloseHandle(fd);
+ continue;
+ }
+
+ adapter = (PSCSI_ADAPTER_BUS_INFO)buffer;
+
+ for(i = 0; i < adapter->NumberOfBuses; i++) {
+
+ if (adapter->BusData[i].InquiryDataOffset == 0) {
+ /* No device here */
+ continue;
+ }
+
+ inquiry = (PSCSI_INQUIRY_DATA) (buffer +
+ adapter->BusData[i].InquiryDataOffset);
+ while(1) {
+ /* Check if it is a scanner or a processor
+ * device. Ignore the other
+ * device types. */
+ if (inquiry->InquiryDataLength >= 5 &&
+ ((inquiry->InquiryData[0] & 0x1f) == 3 ||
+ (inquiry->InquiryData[0] & 0x1f) == 6)) {
+ char device_name[20];
+ sprintf(device_name, "h%db%dt%dl%d", hca, inquiry->PathId, inquiry->TargetId, inquiry->Lun);
+ dev_list[dev_list_index] = strdup(device_name);
+ dev_list_index++;
+ }
+
+ if (inquiry->NextInquiryDataOffset == 0) {
+ /* No device here */
+ break;
+ } else {
+ inquiry = (PSCSI_INQUIRY_DATA) (buffer +
+ inquiry->NextInquiryDataOffset);
+ }
+ }
+ }
+
+ CloseHandle(fd);
+
+ }
+
+ return dev_list;
+
+}
+#endif
+
+#if defined (HAVE_IOKIT_CDB_IOSCSILIB_H) || \
+ defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
+ defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
+char **scsi_dev_list;
+int scsi_dev_list_index;
+
+static SANE_Status AddToSCSIDeviceList (const char *dev) {
+ if (scsi_dev_list_index < 99) {
+ scsi_dev_list [scsi_dev_list_index] = strdup (dev);
+ scsi_dev_list_index++;
+ return SANE_STATUS_GOOD;
+ }
+ else
+ return SANE_STATUS_NO_MEM;
+}
+
+static char **build_scsi_dev_list(void)
+{
+ scsi_dev_list_index = 0;
+ scsi_dev_list = malloc (100 * sizeof(char *));
+ sanei_scsi_find_devices (NULL, NULL, NULL, -1, -1, -1, -1,
+ AddToSCSIDeviceList);
+ scsi_dev_list [scsi_dev_list_index] = NULL;
+ return scsi_dev_list;
+}
+#endif
+
+static int
+check_mustek_pp_device (void)
+{
+ const char **devices;
+ int ctr = 0, found = 0, scsi = 0;
+
+ if (verbose > 1)
+ printf ("searching for Mustek parallel port scanners:\n");
+
+ devices = sanei_pa4s2_devices ();
+
+ while (devices[ctr] != NULL) {
+ int fd;
+ SANE_Status result;
+
+ /* ordinary parallel port scanner type */
+ if (verbose > 1)
+ printf ("checking %s...", devices[ctr]);
+
+ result = sanei_pa4s2_open (devices[ctr], &fd);
+
+ if (verbose > 1)
+ {
+ if (result != 0)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ else
+ printf (" open ok\n");
+ }
+
+ if (result == 0) {
+ printf ("found possible Mustek parallel port scanner at \"%s\"\n",
+ devices[ctr]);
+ found++;
+ sanei_pa4s2_close(fd);
+ }
+
+ /* trying scsi over pp devices */
+ if (verbose > 1)
+ printf ("checking %s (SCSI emulation)...", devices[ctr]);
+
+ result = sanei_pa4s2_scsi_pp_open (devices[ctr], &fd);
+
+ if (verbose > 1)
+ {
+ if (result != 0)
+ printf (" failed to open (%s)\n", sane_strstatus (result));
+ else
+ printf (" open ok\n");
+ }
+
+ if (result == 0) {
+ printf ("found possible Mustek SCSI over PP scanner at \"%s\"\n",
+ devices[ctr]);
+ scsi++;
+ sanei_pa4s2_close(fd);
+ }
+
+ ctr++;
+ }
+
+ free(devices);
+
+ if (found > 0 && verbose > 0)
+ printf("\n # Your Mustek parallel port scanner was detected. It may or\n"
+ " # may not be supported by SANE. Please read the sane-mustek_pp\n"
+ " # man-page for setup instructions.\n");
+
+ if (scsi > 0 && verbose > 0)
+ printf("\n # Your Mustek parallel port scanner was detected. It may or\n"
+ " # may not be supported by SANE. Please read the sane-mustek_pp\n"
+ " # man-page for setup instructions.\n");
+
+ return (found > 0 || scsi > 0);
+}
+
+#ifdef HAVE_LIBUSB
+static SANE_Bool
+parse_num (char* search, const char* line, int base, long int * number)
+{
+ char* start_number;
+
+ start_number = strstr (line, search);
+ if (start_number == NULL)
+ return SANE_FALSE;
+ start_number += strlen (search);
+
+ *number = strtol (start_number, NULL, base);
+ if (verbose > 2)
+ printf ("Found %s%ld\n", search, *number);
+ return SANE_TRUE;
+}
+
+static SANE_Bool
+parse_bcd (char* search, const char* line, long int * number)
+{
+ char* start_number;
+ char* end_number;
+ int first_part;
+ int second_part;
+
+ start_number = strstr (line, search);
+ if (start_number == NULL)
+ return SANE_FALSE;
+ start_number += strlen (search);
+
+ first_part = strtol (start_number, &end_number, 10);
+ start_number = end_number + 1; /* skip colon */
+ second_part = strtol (start_number, NULL, 10);
+ *number = ((first_part / 10) << 12) + ((first_part % 10) << 8)
+ + ((second_part / 10) << 4) + (second_part % 10);
+ if (verbose > 2)
+ printf ("Found %s%ld\n", search, *number);
+ return SANE_TRUE;
+}
+
+static void
+parse_file (char *filename)
+{
+ FILE * parsefile;
+ char line [PATH_MAX], *token;
+ const char * p;
+ struct usb_device *dev = 0;
+ long int number = 0;
+ int current_config = 1;
+ int current_if = -1;
+ int current_as = -1;
+ int current_ep = -1;
+
+ if (verbose > 1)
+ printf ("trying to open %s\n", filename);
+ parsefile = fopen (filename, "r");
+
+ if (parsefile == NULL)
+ {
+ if (verbose > 0)
+ printf ("opening %s failed: %s\n", filename, strerror (errno));
+ return;
+ }
+
+ while (sanei_config_read (line, PATH_MAX, parsefile))
+ {
+ if (verbose > 2)
+ printf ("parsing line: `%s'\n", line);
+ p = sanei_config_get_string (line, &token);
+ if (!token || !p || token[0] == '\0')
+ continue;
+ if (token[1] != ':')
+ {
+ if (verbose > 2)
+ printf ("missing `:'?\n");
+ continue;
+ }
+ switch (token[0])
+ {
+ case 'T':
+ if (dev)
+ check_libusb_device (dev, SANE_TRUE);
+ dev = calloc (1, sizeof (struct usb_device));
+ dev->bus = calloc (1, sizeof (struct usb_bus));
+ current_config = 1;
+ current_if = -1;
+ current_as = -1;
+ current_ep = -1;
+ break;
+ case 'D':
+ if (parse_bcd ("Ver=", line, &number))
+ dev->descriptor.bcdUSB = number;
+ if (parse_num ("Cls=", line, 16, &number))
+ dev->descriptor.bDeviceClass = number;
+ if (parse_num ("Sub=", line, 16, &number))
+ dev->descriptor.bDeviceSubClass = number;
+ if (parse_num ("Prot=", line, 16, &number))
+ dev->descriptor.bDeviceProtocol = number;
+ if (parse_num ("MxPS=", line, 10, &number))
+ dev->descriptor.bMaxPacketSize0 = number;
+ if (parse_num ("#Cfgs=", line, 10, &number))
+ dev->descriptor.bNumConfigurations = number;
+ dev->config = calloc (number, sizeof (struct usb_config_descriptor));
+ break;
+ case 'P':
+ if (parse_num ("Vendor=", line, 16, &number))
+ dev->descriptor.idVendor = number;
+ if (parse_num ("ProdID=", line, 16, &number))
+ dev->descriptor.idProduct = number;
+ if (parse_bcd ("Rev=", line, &number))
+ dev->descriptor.bcdDevice = number;
+ break;
+ case 'C':
+ current_if = -1;
+ current_as = -1;
+ current_ep = -1;
+ if (parse_num ("Cfg#=", line, 10, &number))
+ {
+ current_config = number - 1;
+ dev->config[current_config].bConfigurationValue = number;
+ }
+ if (parse_num ("Ifs=", line, 10, &number))
+ dev->config[current_config].bNumInterfaces = number;
+ dev->config[current_config].interface
+ = calloc (number, sizeof (struct usb_interface));
+ if (parse_num ("Atr=", line, 16, &number))
+ dev->config[current_config].bmAttributes = number;
+ if (parse_num ("MxPwr=", line, 10, &number))
+ dev->config[current_config].MaxPower = number / 2;
+ break;
+ case 'I':
+ current_ep = -1;
+ if (parse_num ("If#=", line, 10, &number))
+ {
+ if (current_if != number)
+ {
+ current_if = number;
+ current_as = -1;
+ dev->config[current_config].interface[current_if].altsetting
+ = calloc (20, sizeof (struct usb_interface_descriptor));
+ /* Can't read number of altsettings */
+ dev->config[current_config].interface[current_if].num_altsetting = 1;
+ }
+ else
+ dev->config[current_config].interface[current_if].num_altsetting++;
+ }
+ if (parse_num ("Alt=", line, 10, &number))
+ {
+ current_as = number;
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceNumber
+ = current_if;
+ dev->config[current_config].interface[current_if].altsetting[current_as].bAlternateSetting
+ = current_as;
+ }
+ if (parse_num ("#EPs=", line, 10, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bNumEndpoints
+ = number;
+ dev->config[current_config].interface[current_if].altsetting[current_as].endpoint
+ = calloc (number, sizeof (struct usb_endpoint_descriptor));
+ if (parse_num ("Cls=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceClass
+ = number;
+ if (parse_num ("Sub=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceSubClass
+ = number;
+ if (parse_num ("Prot=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as].bInterfaceProtocol
+ = number;
+ break;
+ case 'E':
+ current_ep++;
+ if (parse_num ("Ad=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].bEndpointAddress = number;
+ if (parse_num ("Atr=", line, 16, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].bmAttributes = number;
+ if (parse_num ("MxPS=", line, 10, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].wMaxPacketSize = number;
+ if (parse_num ("Ivl=", line, 10, &number))
+ dev->config[current_config].interface[current_if].altsetting[current_as]
+ .endpoint[current_ep].bInterval = number;
+ break;
+ case 'S':
+ case 'B':
+ continue;
+ default:
+ if (verbose > 1)
+ printf ("ignoring unknown line identifier: %c\n", token[0]);
+ continue;
+ }
+ free (token);
+ }
+ if (dev)
+ check_libusb_device (dev, SANE_TRUE);
+ fclose (parsefile);
+ return;
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+ char **dev_list, **usb_dev_list, *dev_name, **ap;
+ int enable_pp_checks = SANE_FALSE;
+
+ prog_name = strrchr (argv[0], '/');
+ if (prog_name)
+ ++prog_name;
+ else
+ prog_name = argv[0];
+
+ for (ap = argv + 1; ap < argv + argc; ++ap)
+ {
+ if ((*ap)[0] != '-')
+ break;
+ switch ((*ap)[1])
+ {
+ case '?':
+ case 'h':
+ usage (0);
+ exit (0);
+
+ case 'v':
+ ++verbose;
+ break;
+
+ case 'q':
+ --verbose;
+ break;
+
+ case 'f':
+ force = SANE_TRUE;
+ break;
+
+ case 'p':
+ enable_pp_checks = SANE_TRUE;
+ break;
+
+ case 'F':
+#ifdef HAVE_LIBUSB
+ parse_file ((char *) (*(++ap)));
+#elif defined(HAVE_LIBUSB_1_0)
+ printf ("option -F not implemented with libusb-1.0\n");
+#else
+ printf ("libusb not available: option -F can't be used\n");
+#endif
+ exit (0);
+
+ default:
+ printf ("unknown option: -%c, try -h for help\n", (*ap)[1]);
+ exit (0);
+ }
+ }
+ if (ap < argv + argc)
+ {
+ dev_list = ap;
+ usb_dev_list = ap;
+ }
+ else
+ {
+ static char *default_dev_list[] = {
+#if defined(__sgi)
+ "/dev/scsi/sc0d1l0", "/dev/scsi/sc0d2l0",
+ "/dev/scsi/sc0d3l0", "/dev/scsi/sc0d4l0",
+ "/dev/scsi/sc0d5l0", "/dev/scsi/sc0d6l0",
+ "/dev/scsi/sc0d7l0", "/dev/scsi/sc0d8l0",
+ "/dev/scsi/sc0d9l0", "/dev/scsi/sc0d10l0",
+ "/dev/scsi/sc0d11l0", "/dev/scsi/sc0d12l0",
+ "/dev/scsi/sc0d13l0", "/dev/scsi/sc0d14l0",
+ "/dev/scsi/sc0d15l0",
+ "/dev/scsi/sc1d1l0", "/dev/scsi/sc1d2l0",
+ "/dev/scsi/sc1d3l0", "/dev/scsi/sc1d4l0",
+ "/dev/scsi/sc1d5l0", "/dev/scsi/sc1d6l0",
+ "/dev/scsi/sc1d7l0", "/dev/scsi/sc1d8l0",
+ "/dev/scsi/sc1d9l0", "/dev/scsi/sc1d10l0",
+ "/dev/scsi/sc1d11l0", "/dev/scsi/sc1d12l0",
+ "/dev/scsi/sc1d13l0", "/dev/scsi/sc1d14l0",
+ "/dev/scsi/sc1d15l0",
+ "/dev/scsi/sc2d1l0", "/dev/scsi/sc2d2l0",
+ "/dev/scsi/sc2d3l0", "/dev/scsi/sc2d4l0",
+ "/dev/scsi/sc2d5l0", "/dev/scsi/sc2d6l0",
+ "/dev/scsi/sc2d7l0", "/dev/scsi/sc2d8l0",
+ "/dev/scsi/sc2d9l0", "/dev/scsi/sc2d10l0",
+ "/dev/scsi/sc2d11l0", "/dev/scsi/sc2d12l0",
+ "/dev/scsi/sc2d13l0", "/dev/scsi/sc2d14l0",
+ "/dev/scsi/sc2d15l0",
+ "/dev/scsi/sc3d1l0", "/dev/scsi/sc3d2l0",
+ "/dev/scsi/sc3d3l0", "/dev/scsi/sc3d4l0",
+ "/dev/scsi/sc3d5l0", "/dev/scsi/sc3d6l0",
+ "/dev/scsi/sc3d7l0", "/dev/scsi/sc3d8l0",
+ "/dev/scsi/sc3d9l0", "/dev/scsi/sc3d10l0",
+ "/dev/scsi/sc3d11l0", "/dev/scsi/sc3d12l0",
+ "/dev/scsi/sc3d13l0", "/dev/scsi/sc3d14l0",
+ "/dev/scsi/sc3d15l0",
+ "/dev/scsi/sc4d1l0", "/dev/scsi/sc4d2l0",
+ "/dev/scsi/sc4d3l0", "/dev/scsi/sc4d4l0",
+ "/dev/scsi/sc4d5l0", "/dev/scsi/sc4d6l0",
+ "/dev/scsi/sc4d7l0", "/dev/scsi/sc4d8l0",
+ "/dev/scsi/sc4d9l0", "/dev/scsi/sc4d10l0",
+ "/dev/scsi/sc4d11l0", "/dev/scsi/sc4d12l0",
+ "/dev/scsi/sc4d13l0", "/dev/scsi/sc4d14l0",
+ "/dev/scsi/sc4d15l0",
+ "/dev/scsi/sc5d1l0", "/dev/scsi/sc5d2l0",
+ "/dev/scsi/sc5d3l0", "/dev/scsi/sc5d4l0",
+ "/dev/scsi/sc5d5l0", "/dev/scsi/sc5d6l0",
+ "/dev/scsi/sc5d7l0", "/dev/scsi/sc5d8l0",
+ "/dev/scsi/sc5d9l0", "/dev/scsi/sc5d10l0",
+ "/dev/scsi/sc5d11l0", "/dev/scsi/sc5d12l0",
+ "/dev/scsi/sc5d13l0", "/dev/scsi/sc5d14l0",
+ "/dev/scsi/sc5d15l0",
+ "/dev/scsi/sc6d1l0", "/dev/scsi/sc6d2l0",
+ "/dev/scsi/sc6d3l0", "/dev/scsi/sc6d4l0",
+ "/dev/scsi/sc6d5l0", "/dev/scsi/sc6d6l0",
+ "/dev/scsi/sc6d7l0", "/dev/scsi/sc6d8l0",
+ "/dev/scsi/sc6d9l0", "/dev/scsi/sc6d10l0",
+ "/dev/scsi/sc6d11l0", "/dev/scsi/sc6d12l0",
+ "/dev/scsi/sc6d13l0", "/dev/scsi/sc6d14l0",
+ "/dev/scsi/sc6d15l0",
+ "/dev/scsi/sc7d1l0", "/dev/scsi/sc7d2l0",
+ "/dev/scsi/sc7d3l0", "/dev/scsi/sc7d4l0",
+ "/dev/scsi/sc7d5l0", "/dev/scsi/sc7d6l0",
+ "/dev/scsi/sc7d7l0", "/dev/scsi/sc7d8l0",
+ "/dev/scsi/sc7d9l0", "/dev/scsi/sc7d10l0",
+ "/dev/scsi/sc7d11l0", "/dev/scsi/sc7d12l0",
+ "/dev/scsi/sc7d13l0", "/dev/scsi/sc7d14l0",
+ "/dev/scsi/sc7d15l0",
+ "/dev/scsi/sc8d1l0", "/dev/scsi/sc8d2l0",
+ "/dev/scsi/sc8d3l0", "/dev/scsi/sc8d4l0",
+ "/dev/scsi/sc8d5l0", "/dev/scsi/sc8d6l0",
+ "/dev/scsi/sc8d7l0", "/dev/scsi/sc8d8l0",
+ "/dev/scsi/sc8d9l0", "/dev/scsi/sc8d10l0",
+ "/dev/scsi/sc8d11l0", "/dev/scsi/sc8d12l0",
+ "/dev/scsi/sc8d13l0", "/dev/scsi/sc8d14l0",
+ "/dev/scsi/sc8d15l0",
+ "/dev/scsi/sc9d1l0", "/dev/scsi/sc9d2l0",
+ "/dev/scsi/sc9d3l0", "/dev/scsi/sc9d4l0",
+ "/dev/scsi/sc9d5l0", "/dev/scsi/sc9d6l0",
+ "/dev/scsi/sc9d7l0", "/dev/scsi/sc9d8l0",
+ "/dev/scsi/sc9d9l0", "/dev/scsi/sc9d10l0",
+ "/dev/scsi/sc9d11l0", "/dev/scsi/sc9d12l0",
+ "/dev/scsi/sc9d13l0", "/dev/scsi/sc9d14l0",
+ "/dev/scsi/sc9d15l0",
+ "/dev/scsi/sc10d1l0", "/dev/scsi/sc10d2l0",
+ "/dev/scsi/sc10d3l0", "/dev/scsi/sc10d4l0",
+ "/dev/scsi/sc10d5l0", "/dev/scsi/sc10d6l0",
+ "/dev/scsi/sc10d7l0", "/dev/scsi/sc10d8l0",
+ "/dev/scsi/sc10d9l0", "/dev/scsi/sc10d10l0",
+ "/dev/scsi/sc10d11l0", "/dev/scsi/sc10d12l0",
+ "/dev/scsi/sc10d13l0", "/dev/scsi/sc10d14l0",
+ "/dev/scsi/sc10d15l0",
+ "/dev/scsi/sc11d1l0", "/dev/scsi/sc11d2l0",
+ "/dev/scsi/sc11d3l0", "/dev/scsi/sc11d4l0",
+ "/dev/scsi/sc11d5l0", "/dev/scsi/sc11d6l0",
+ "/dev/scsi/sc11d7l0", "/dev/scsi/sc11d8l0",
+ "/dev/scsi/sc11d9l0", "/dev/scsi/sc11d10l0",
+ "/dev/scsi/sc11d11l0", "/dev/scsi/sc11d12l0",
+ "/dev/scsi/sc11d13l0", "/dev/scsi/sc11d14l0",
+ "/dev/scsi/sc11d15l0",
+ "/dev/scsi/sc12d1l0", "/dev/scsi/sc12d2l0",
+ "/dev/scsi/sc12d3l0", "/dev/scsi/sc12d4l0",
+ "/dev/scsi/sc12d5l0", "/dev/scsi/sc12d6l0",
+ "/dev/scsi/sc12d7l0", "/dev/scsi/sc12d8l0",
+ "/dev/scsi/sc12d9l0", "/dev/scsi/sc12d10l0",
+ "/dev/scsi/sc12d11l0", "/dev/scsi/sc12d12l0",
+ "/dev/scsi/sc12d13l0", "/dev/scsi/sc12d14l0",
+ "/dev/scsi/sc12d15l0",
+ "/dev/scsi/sc13d1l0", "/dev/scsi/sc13d2l0",
+ "/dev/scsi/sc13d3l0", "/dev/scsi/sc13d4l0",
+ "/dev/scsi/sc13d5l0", "/dev/scsi/sc13d6l0",
+ "/dev/scsi/sc13d7l0", "/dev/scsi/sc13d8l0",
+ "/dev/scsi/sc13d9l0", "/dev/scsi/sc13d10l0",
+ "/dev/scsi/sc13d11l0", "/dev/scsi/sc13d12l0",
+ "/dev/scsi/sc13d13l0", "/dev/scsi/sc13d14l0",
+ "/dev/scsi/sc13d15l0",
+ "/dev/scsi/sc14d1l0", "/dev/scsi/sc14d2l0",
+ "/dev/scsi/sc14d3l0", "/dev/scsi/sc14d4l0",
+ "/dev/scsi/sc14d5l0", "/dev/scsi/sc14d6l0",
+ "/dev/scsi/sc14d7l0", "/dev/scsi/sc14d8l0",
+ "/dev/scsi/sc14d9l0", "/dev/scsi/sc14d10l0",
+ "/dev/scsi/sc14d11l0", "/dev/scsi/sc14d12l0",
+ "/dev/scsi/sc14d13l0", "/dev/scsi/sc14d14l0",
+ "/dev/scsi/sc14d15l0",
+ "/dev/scsi/sc15d1l0", "/dev/scsi/sc15d2l0",
+ "/dev/scsi/sc15d3l0", "/dev/scsi/sc15d4l0",
+ "/dev/scsi/sc15d5l0", "/dev/scsi/sc15d6l0",
+ "/dev/scsi/sc15d7l0", "/dev/scsi/sc15d8l0",
+ "/dev/scsi/sc15d9l0", "/dev/scsi/sc15d10l0",
+ "/dev/scsi/sc15d11l0", "/dev/scsi/sc15d12l0",
+ "/dev/scsi/sc15d13l0", "/dev/scsi/sc15d14l0",
+ "/dev/scsi/sc15d15l0",
+#elif defined(__EMX__)
+ "b0t0l0", "b0t1l0", "b0t2l0", "b0t3l0",
+ "b0t4l0", "b0t5l0", "b0t6l0", "b0t7l0",
+ "b1t0l0", "b1t1l0", "b1t2l0", "b1t3l0",
+ "b1t4l0", "b1t5l0", "b1t6l0", "b1t7l0",
+ "b2t0l0", "b2t1l0", "b2t2l0", "b2t3l0",
+ "b2t4l0", "b2t5l0", "b2t6l0", "b2t7l0",
+ "b3t0l0", "b3t1l0", "b3t2l0", "b3t3l0",
+ "b3t4l0", "b3t5l0", "b3t6l0", "b3t7l0",
+#elif defined(__linux__)
+ "/dev/scanner",
+ "/dev/sg0", "/dev/sg1", "/dev/sg2", "/dev/sg3",
+ "/dev/sg4", "/dev/sg5", "/dev/sg6", "/dev/sg7",
+ "/dev/sg8", "/dev/sg9",
+ "/dev/sga", "/dev/sgb", "/dev/sgc", "/dev/sgd",
+ "/dev/sge", "/dev/sgf", "/dev/sgg", "/dev/sgh",
+ "/dev/sgi", "/dev/sgj", "/dev/sgk", "/dev/sgl",
+ "/dev/sgm", "/dev/sgn", "/dev/sgo", "/dev/sgp",
+ "/dev/sgq", "/dev/sgr", "/dev/sgs", "/dev/sgt",
+ "/dev/sgu", "/dev/sgv", "/dev/sgw", "/dev/sgx",
+ "/dev/sgy", "/dev/sgz",
+#elif defined(__NeXT__)
+ "/dev/sg0a", "/dev/sg0b", "/dev/sg0c", "/dev/sg0d",
+ "/dev/sg0e", "/dev/sg0f", "/dev/sg0g", "/dev/sg0h",
+ "/dev/sg1a", "/dev/sg1b", "/dev/sg1c", "/dev/sg1d",
+ "/dev/sg1e", "/dev/sg1f", "/dev/sg1g", "/dev/sg1h",
+ "/dev/sg2a", "/dev/sg2b", "/dev/sg2c", "/dev/sg2d",
+ "/dev/sg2e", "/dev/sg2f", "/dev/sg2g", "/dev/sg2h",
+ "/dev/sg3a", "/dev/sg3b", "/dev/sg3c", "/dev/sg3d",
+ "/dev/sg3e", "/dev/sg3f", "/dev/sg3g", "/dev/sg3h",
+#elif defined(_AIX)
+ "/dev/scanner",
+ "/dev/gsc0", "/dev/gsc1", "/dev/gsc2", "/dev/gsc3",
+ "/dev/gsc4", "/dev/gsc5", "/dev/gsc6", "/dev/gsc7",
+ "/dev/gsc8", "/dev/gsc9", "/dev/gsc10", "/dev/gsc11",
+ "/dev/gsc12", "/dev/gsc13", "/dev/gsc14", "/dev/gsc15",
+#elif defined(__sun)
+ "/dev/scg0a", "/dev/scg0b", "/dev/scg0c", "/dev/scg0d",
+ "/dev/scg0e", "/dev/scg0f", "/dev/scg0g",
+ "/dev/scg1a", "/dev/scg1b", "/dev/scg1c", "/dev/scg1d",
+ "/dev/scg1e", "/dev/scg1f", "/dev/scg1g",
+ "/dev/scg2a", "/dev/scg2b", "/dev/scg2c", "/dev/scg2d",
+ "/dev/scg2e", "/dev/scg2f", "/dev/scg2g",
+ "/dev/sg/0", "/dev/sg/1", "/dev/sg/2", "/dev/sg/3",
+ "/dev/sg/4", "/dev/sg/5", "/dev/sg/6",
+ "/dev/scsi/scanner/", "/dev/scsi/processor/",
+#elif defined(HAVE_CAMLIB_H)
+ "/dev/scanner", "/dev/scanner0", "/dev/scanner1",
+ "/dev/pass0", "/dev/pass1", "/dev/pass2", "/dev/pass3",
+ "/dev/pass4", "/dev/pass5", "/dev/pass6", "/dev/pass7",
+#elif defined(__FreeBSD__)
+ "/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
+ "/dev/uk5", "/dev/uk6",
+#elif defined(__NetBSD__)
+ "/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
+ "/dev/uk5", "/dev/uk6",
+ "/dev/ss0",
+#elif defined(__OpenBSD__)
+ "/dev/uk0", "/dev/uk1", "/dev/uk2", "/dev/uk3", "/dev/uk4",
+ "/dev/uk5", "/dev/uk6",
+#elif defined(__hpux)
+ "/dev/rscsi/",
+#endif
+ 0
+ };
+ static char *usb_default_dev_list[] = {
+#if defined(__linux__)
+ "/dev/usb/scanner",
+ "/dev/usb/scanner0", "/dev/usb/scanner1",
+ "/dev/usb/scanner2", "/dev/usb/scanner3",
+ "/dev/usb/scanner4", "/dev/usb/scanner5",
+ "/dev/usb/scanner5", "/dev/usb/scanner7",
+ "/dev/usb/scanner8", "/dev/usb/scanner9",
+ "/dev/usb/scanner10", "/dev/usb/scanner11",
+ "/dev/usb/scanner12", "/dev/usb/scanner13",
+ "/dev/usb/scanner14", "/dev/usb/scanner15",
+ "/dev/usbscanner",
+ "/dev/usbscanner0", "/dev/usbscanner1",
+ "/dev/usbscanner2", "/dev/usbscanner3",
+ "/dev/usbscanner4", "/dev/usbscanner5",
+ "/dev/usbscanner6", "/dev/usbscanner7",
+ "/dev/usbscanner8", "/dev/usbscanner9",
+ "/dev/usbscanner10", "/dev/usbscanner11",
+ "/dev/usbscanner12", "/dev/usbscanner13",
+ "/dev/usbscanner14", "/dev/usbscanner15",
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+ "/dev/uscanner",
+ "/dev/uscanner0", "/dev/uscanner1",
+ "/dev/uscanner2", "/dev/uscanner3",
+ "/dev/uscanner4", "/dev/uscanner5",
+ "/dev/uscanner6", "/dev/uscanner7",
+ "/dev/uscanner8", "/dev/uscanner9",
+ "/dev/uscanner10", "/dev/uscanner11",
+ "/dev/uscanner12", "/dev/uscanner13",
+ "/dev/uscanner14", "/dev/uscanner15",
+#endif
+ 0
+ };
+
+#if defined (WIN32_SCSI) || \
+ defined (HAVE_IOKIT_CDB_IOSCSILIB_H) || \
+ defined (HAVE_IOKIT_SCSI_SCSICOMMANDOPERATIONCODES_H) || \
+ defined (HAVE_IOKIT_SCSI_COMMANDS_SCSICOMMANDOPERATIONCODES_H)
+ /* Build a list of valid of possible scanners found */
+ dev_list = build_scsi_dev_list();
+#else
+ dev_list = default_dev_list;
+#endif
+
+ usb_dev_list = usb_default_dev_list;
+ }
+ if (verbose > 1)
+ printf ("This is sane-find-scanner from %s\n", PACKAGE_STRING);
+
+ if (verbose > 0)
+ printf ("\n # sane-find-scanner will now attempt to detect your scanner. If the"
+ "\n # result is different from what you expected, first make sure your"
+ "\n # scanner is powered up and properly connected to your computer.\n\n");
+
+ if (verbose > 1)
+ printf ("searching for SCSI scanners:\n");
+
+ while ((dev_name = *dev_list++))
+ {
+ if (strlen (dev_name) == 0)
+ continue; /* Empty device names ... */
+
+ if (dev_name[strlen (dev_name) - 1] == '/')
+ {
+ /* check whole directories */
+ DIR *dir;
+ char *file_name;
+
+ dir = scan_directory (dev_name);
+ if (!dir)
+ continue;
+
+ while ((file_name = get_next_file (dev_name, dir)))
+ check_scsi_file (file_name);
+ }
+ else
+ {
+ /* check device files */
+ check_scsi_file (dev_name);
+ }
+ }
+ if (device_found)
+ {
+ if (verbose > 0)
+ printf
+ (" # Your SCSI scanner was detected. It may or may not be "
+ "supported by SANE. Try\n # scanimage -L and read the backend's "
+ "manpage.\n");
+ }
+ else
+ {
+ if (verbose > 0)
+ printf
+ (" # No SCSI scanners found. If you expected something different, "
+ "make sure that\n # you have loaded a kernel SCSI driver for your SCSI "
+ "adapter.\n");
+ if (!check_sg ())
+ {
+ if (verbose > 0)
+ printf
+ (" # Also you need support for SCSI Generic (sg) in your "
+ "operating system.\n # If using Linux, try \"modprobe "
+ "sg\".\n");
+ }
+ }
+ if (verbose > 0)
+ printf ("\n");
+ device_found = SANE_FALSE;
+ sanei_usb_init ();
+ if (verbose > 1)
+ printf ("searching for USB scanners:\n");
+
+ while ((dev_name = *usb_dev_list++))
+ {
+ if (strlen (dev_name) == 0)
+ continue; /* Empty device names ... */
+
+ if (dev_name[strlen (dev_name) - 1] == '/')
+ {
+ /* check whole directories */
+ DIR *dir;
+ char *file_name;
+
+ dir = scan_directory (dev_name);
+ if (!dir)
+ continue;
+
+ while ((file_name = get_next_file (dev_name, dir)))
+ check_usb_file (file_name);
+ }
+ else
+ {
+ /* check device files */
+ check_usb_file (dev_name);
+ }
+ }
+#ifdef HAVE_LIBUSB
+ /* Now the libusb devices */
+ {
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ if (ap < argv + argc)
+ {
+ /* user-specified devices not useful for libusb */
+ if (verbose > 1)
+ printf ("ignoring libusb devices\n");
+ }
+ else
+ {
+ if (verbose > 2)
+ printf ("trying libusb:\n");
+ for (bus = usb_get_busses (); bus; bus = bus->next)
+ {
+ for (dev = bus->devices; dev; dev = dev->next)
+ {
+ check_libusb_device (dev, SANE_FALSE);
+ } /* for (dev) */
+ } /* for (bus) */
+ }
+ }
+#elif defined(HAVE_LIBUSB_1_0)
+ /* Now the libusb-1.0 devices */
+ {
+ if (ap < argv + argc)
+ {
+ /* user-specified devices not useful for libusb */
+ if (verbose > 1)
+ printf ("ignoring libusb devices\n");
+ }
+ else
+ {
+ libusb_device **devlist;
+ ssize_t devcnt;
+ int i;
+ int ret;
+
+ if (verbose > 2)
+ printf ("trying libusb:\n");
+
+ ret = libusb_init (&sfs_usb_ctx);
+ if (ret < 0)
+ {
+ printf ("# Could not initialize libusb-1.0, error %d\n", ret);
+ printf ("# Skipping libusb devices\n");
+
+ goto failed_libusb_1_0;
+ }
+
+ if (verbose > 3)
+ libusb_set_debug (sfs_usb_ctx, 3);
+
+ devcnt = libusb_get_device_list (sfs_usb_ctx, &devlist);
+ if (devcnt < 0)
+ {
+ printf ("# Could not get device list, error %d\n", ret);
+
+ goto deinit_libusb_1_0;
+ }
+
+ for (i = 0; i < devcnt; i++)
+ {
+ check_libusb_device (devlist[i], SANE_FALSE);
+ }
+
+ libusb_free_device_list (devlist, 1);
+
+ deinit_libusb_1_0:
+ libusb_exit (sfs_usb_ctx);
+
+ failed_libusb_1_0:
+ ; /* init failed, jumping here */
+ }
+ }
+#else /* not HAVE_LIBUSB && not HAVE_LIBUSB_1_0 */
+ if (verbose > 1)
+ printf ("libusb not available\n");
+#endif /* not HAVE_LIBUSB && not HAVE_LIBUSB_1_0 */
+
+ if (device_found)
+ {
+ if (libusb_device_found)
+ {
+ if (verbose > 0)
+ printf
+ (" # Your USB scanner was (probably) detected. It "
+ "may or may not be supported by\n # SANE. Try scanimage "
+ "-L and read the backend's manpage.\n");
+ }
+ else if (verbose > 0)
+ printf
+ (" # Your USB scanner was detected. It may or may not "
+ "be supported by\n # SANE. Try scanimage -L and read the "
+ "backend's manpage.\n");
+ if (unknown_found && verbose > 0)
+ printf
+ (" # `UNKNOWN vendor and product' means that there seems to be a "
+ "scanner at this\n # device file but the vendor and product ids "
+ "couldn't be identified.\n # Currently identification only works "
+ "with Linux versions >= 2.4.8. You may\n # need to configure your "
+ "backend manually, see the backend's manpage.\n");
+ }
+ else
+ {
+ if (verbose > 0)
+ printf
+ (" # No USB scanners found. If you expected something different, "
+ "make sure that\n # you have loaded a kernel driver for your USB host "
+ "controller and have setup\n # the USB system correctly. "
+ "See man sane-usb for details.\n");
+#if !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUSB_1_0)
+ if (verbose > 0)
+ printf (" # SANE has been built without libusb support. This may be a "
+ "reason\n # for not detecting USB scanners. Read README for "
+ "more details.\n");
+#endif
+ }
+ if (enable_pp_checks == SANE_TRUE)
+ {
+ if (!check_mustek_pp_device() && verbose > 0)
+ printf ("\n # No Mustek parallel port scanners found. If you expected"
+ " something\n # different, make sure the scanner is correctly"
+ " connected to your computer\n # and you have apropriate"
+ " access rights.\n");
+ }
+ else if (verbose > 0)
+ printf ("\n # Not checking for parallel port scanners.\n");
+ if (verbose > 0)
+ printf ("\n # Most Scanners connected to the parallel port or other "
+ "proprietary ports\n # can't be detected by this program.\n");
+#ifdef HAVE_GETUID
+ if (getuid ())
+ if (verbose > 0)
+ printf
+ ("\n # You may want to run this program as root to find all devices. "
+ "Once you\n # found the scanner devices, be sure to adjust access "
+ "permissions as\n # necessary.\n");
+#endif
+
+ if (verbose > 1)
+ printf ("done\n");
+
+ return 0;
+}
diff --git a/tools/umax_pp.c b/tools/umax_pp.c
new file mode 100644
index 0000000..134320b
--- /dev/null
+++ b/tools/umax_pp.c
@@ -0,0 +1,573 @@
+/*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version
+* 2 of the License, or (at your option) any later version.
+*/
+
+/* For putenv */
+#define _XOPEN_SOURCE
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#define __MAIN__
+
+#include "../backend/umax_pp_low.h"
+#include "../backend/umax_pp_mid.h"
+
+static void
+Usage (char *name)
+{
+ fprintf (stderr,
+ "%s [-c color_mode] [-x coord] [-y coord] [-w width] [-h height] [-g gain] [-z offset] [-d dpi] [-t level] [-s] [-p] [-l 0|1] [-a ioport_addr] [-r]\n",
+ name);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ char dbgstr[80];
+ int probe = 0;
+ int port = 0;
+ char *name = NULL;
+ int scan = 0;
+ int lamp = -1;
+ int i, fd;
+ int found;
+ int recover = 0;
+ int trace = 0;
+ int maxw, maxh;
+
+/* scanning parameters : defaults to preview (75 dpi color, full scan area) */
+ int gain = 0x0;
+ int offset = 0x646;
+ int dpi = 75;
+ int x = 0, y = 0;
+ int width = -1, height = -1;
+ int color = RGB_MODE;
+
+ char **ports;
+ int rc;
+
+
+ /* option parsing */
+ /*
+ -c --color : color mode: RGB, BW, BW12, RGB12
+ -x : x coordinate
+ -y : y coordinate
+ -w --witdh : scan width
+ -h --height : scan height
+ -f --file : session file
+ -p --probe : probe scanner
+ -s --scan : scan
+ -t --trace : execution trace
+ -l --lamp : turn lamp on/off 1/0
+ -d --dpi : set scan resolution
+ -g --gain : set RVB gain
+ -z --offset: set offset
+ -a --addr : io port address
+ -n --name : ppdev device name
+ -r : recover from previous failed scan
+ -m --model : model revision
+ */
+
+
+ i = 1;
+ trace = 0;
+ sanei_umax_pp_setauto (1);
+ while (i < argc)
+ {
+ found = 0;
+
+ if ((strcmp (argv[i], "-p") == 0) || (strcmp (argv[i], "--probe") == 0))
+ {
+ probe = 1;
+ found = 1;
+ }
+
+ if ((strcmp (argv[i], "-c") == 0) || (strcmp (argv[i], "--color") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected color mode value\n");
+ return 0;
+ }
+ color = 0;
+ i++;
+ found = 1;
+ if (strcmp (argv[i], "RGB") == 0)
+ color = RGB_MODE;
+ if (strcmp (argv[i], "RGB12") == 0)
+ color = RGB12_MODE;
+ if (strcmp (argv[i], "BW") == 0)
+ color = BW_MODE;
+ if (strcmp (argv[i], "BW12") == 0)
+ color = BW12_MODE;
+ if (color == 0)
+ {
+ fprintf (stderr, "unexpected color mode value <%s>\n", argv[i]);
+ fprintf (stderr, "Must be RGB, RGB12, BW, or BW12\n");
+ return 0;
+ }
+ }
+
+
+ if (strcmp (argv[i], "-x") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected x value\n");
+ return 0;
+ }
+ x = atoi (argv[i + 1]);
+ i++;
+ found = 1;
+ }
+
+ if (strcmp (argv[i], "-y") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected y value\n");
+ return 0;
+ }
+ y = atoi (argv[i + 1]);
+ i++;
+ found = 1;
+ }
+
+ if ((strcmp (argv[i], "-w") == 0) || (strcmp (argv[i], "--witdh") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected width value\n");
+ return 0;
+ }
+ width = atoi (argv[i + 1]);
+ i++;
+ found = 1;
+ }
+
+ if ((strcmp (argv[i], "-h") == 0)
+ || (strcmp (argv[i], "--height") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected height value\n");
+ return 0;
+ }
+ height = atoi (argv[i + 1]);
+ i++;
+ found = 1;
+ }
+
+ if ((strcmp (argv[i], "-t") == 0) || (strcmp (argv[i], "--trace") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected trace value\n");
+ return 0;
+ }
+ trace = atoi (argv[i + 1]);
+ i++;
+ found = 1;
+ }
+
+
+ if ((strcmp (argv[i], "-r") == 0)
+ || (strcmp (argv[i], "--recover") == 0))
+ {
+ recover = 1;
+ found = 1;
+ }
+
+ if ((strcmp (argv[i], "-s") == 0) || (strcmp (argv[i], "--scan") == 0))
+ {
+ scan = 1;
+ /* we have to probe again if we scan */
+ probe = 1;
+ found = 1;
+ }
+
+ if ((strcmp (argv[i], "-d") == 0) || (strcmp (argv[i], "--dpi") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected dpi value\n");
+ return 0;
+ }
+ dpi = atoi (argv[i + 1]);
+ if ((dpi < 75) || (dpi > 1200))
+ {
+ fprintf (stderr, "dpi value has to be between 75 and 1200\n");
+ return 0;
+ }
+ if ((dpi != 75)
+ && (dpi != 150)
+ && (dpi != 300) && (dpi != 600) && (dpi != 1200))
+ {
+ fprintf (stderr,
+ "dpi value has to be 75, 150, 300, 600 or 1200\n");
+ return 0;
+ }
+ i++;
+ found = 1;
+ }
+
+ if ((strcmp (argv[i], "-g") == 0)
+ || (strcmp (argv[i], "--gain") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected hex gain value ( ex: A59 )\n");
+ return 0;
+ }
+ i++;
+ found = 1;
+ if (strlen (argv[i]) != 3)
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected hex gain value ( ex: A59 )\n");
+ return 0;
+ }
+ gain = strtol (argv[i], NULL, 16);
+ sanei_umax_pp_setauto (0);
+ }
+
+ if ((strcmp (argv[i], "-z") == 0)
+ || (strcmp (argv[i], "--offset") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected hex offset value ( ex: A59 )\n");
+ return 0;
+ }
+ i++;
+ found = 1;
+ if (strlen (argv[i]) != 3)
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected hex offset value ( ex: A59 )\n");
+ return 0;
+ }
+ offset = strtol (argv[i], NULL, 16);
+ }
+
+ if ((strcmp (argv[i], "-n") == 0) || (strcmp (argv[i], "--name") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr,
+ "expected device name ( ex: /dev/parport0 )\n");
+ return 0;
+ }
+ i++;
+ found = 1;
+ name = argv[i];
+ }
+ if ((strcmp (argv[i], "-a") == 0) || (strcmp (argv[i], "--addr") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected hex io port value ( ex: 3BC )\n");
+ return 0;
+ }
+ i++;
+ found = 1;
+ if ((strlen (argv[i]) < 3) || (strlen (argv[i]) > 4))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected hex io port value ( ex: 378 )\n");
+ return 0;
+ }
+ port = strtol (argv[i], NULL, 16);
+ }
+
+
+ if ((strcmp (argv[i], "-l") == 0) || (strcmp (argv[i], "--lamp") == 0))
+ {
+ if (i == (argc - 1))
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "expected lamp value\n");
+ return 0;
+ }
+ lamp = atoi (argv[i + 1]);
+ i++;
+ found = 1;
+ }
+
+ if (!found)
+ {
+ Usage (argv[0]);
+ fprintf (stderr, "unexpected argument <%s>\n", argv[i]);
+ return 0;
+ }
+
+ /* next arg */
+ i++;
+ }
+
+ /* since we use DBG, we have to set env var */
+ /* according to the required trace level */
+ if (trace)
+ {
+ sprintf (dbgstr, "SANE_DEBUG_UMAX_PP_LOW=%d", trace);
+ putenv (dbgstr);
+ }
+
+ /* no address or device given */
+ rc = 0;
+ if ((name == NULL) && (port == 0))
+ {
+ /* safe tests: user parallel port devices */
+ ports = sanei_parport_find_device ();
+ if (ports != NULL)
+ {
+ i = 0;
+ rc = 0;
+ while ((ports[i] != NULL) && (rc != 1))
+ {
+ rc = sanei_umax_pp_initPort (port, ports[i]);
+ i++;
+ }
+ }
+
+ /* try for direct hardware access */
+ if (rc != 1)
+ {
+ ports = sanei_parport_find_port ();
+ i = 0;
+ rc = 0;
+ while ((ports[i] != NULL) && (rc != 1))
+ {
+ rc = sanei_umax_pp_initPort (strtol (ports[i], NULL, 16), NULL);
+ i++;
+ }
+ }
+ if (rc != 1)
+ {
+ fprintf (stderr, "failed to detect a valid device or port!\n");
+ return 0;
+ }
+ }
+ else
+ {
+ if (sanei_umax_pp_initPort (port, name) != 1)
+ {
+ if (port)
+ fprintf (stderr, "failed to gain direct acces to port 0x%X!\n",
+ port);
+ else
+ fprintf (stderr, "failed to gain acces to device %s!\n", name);
+ return 0;
+ }
+ }
+ if (trace)
+ {
+ printf
+ ("UMAX 610P/1220P/2000P scanning program version 6.4 starting ...\n");
+#ifdef HAVE_LINUX_PPDEV_H
+ printf ("ppdev character device built-in.\n");
+#endif
+#ifdef ENABLE_PARPORT_DIRECTIO
+ printf ("direct hardware access built-in.\n");
+#endif
+ }
+
+
+ /* scanning is the default behaviour */
+ if ((!scan) && (lamp < 0) && (!probe))
+ scan = 1;
+
+
+ /* probe scanner */
+ if ((probe) || (lamp >= 0))
+ {
+ printf ("Probing scanner ....\n");
+ if (sanei_umax_pp_probeScanner (recover) != 1)
+ {
+ if (recover)
+ {
+ sanei_umax_pp_initTransport (recover);
+ sanei_umax_pp_endSession ();
+ if (sanei_umax_pp_probeScanner (recover) != 1)
+ {
+ printf ("Recover failed ....\n");
+ return 0;
+ }
+ printf ("Recover done !\n");
+ }
+ else
+ return 0;
+ }
+
+ /* could be written better .... but it is only test */
+ sanei_umax_pp_endSession ();
+
+ /* init transport layer */
+ if (sanei_umax_pp_initTransport (0) != 1)
+ {
+ printf ("initTransport() failed (%s:%d)\n", __FILE__, __LINE__);
+ return 0;
+ }
+ i = sanei_umax_pp_checkModel ();
+ if (i < 600)
+ {
+ sanei_umax_pp_endSession ();
+ printf ("checkModel() failed (%s:%d)\n", __FILE__, __LINE__);
+ return 0;
+ }
+ printf ("UMAX Astra %dP detected \n", i);
+
+ /* free scanner if a scan is planned */
+ if (scan)
+ sanei_umax_pp_endSession ();
+ printf ("Done ....\n");
+ }
+
+ /* lamp on/off: must come after probing (610p handling) */
+ if (lamp >= 0)
+ {
+ /* init transport layer */
+ if (trace)
+ printf ("Tryning to set lamp %s\n", lamp ? "on" : "off");
+ if (sanei_umax_pp_initTransport (recover) != 1)
+ {
+ printf ("initTransport() failed (%s:%d)\n", __FILE__, __LINE__);
+ return 0;
+ }
+ else
+ {
+ if (trace)
+ printf ("initTransport passed...\n");
+ }
+ if (sanei_umax_pp_setLamp (lamp) == 0)
+ {
+ fprintf (stderr, "Setting lamp state failed!\n");
+ return 0;
+ }
+ else
+ {
+ if (trace)
+ printf ("sanei_umax_pp_setLamp passed...\n");
+ }
+ }
+
+ /* scan */
+ if (scan)
+ {
+ printf ("Scanning ....\n");
+ if (sanei_umax_pp_getastra () < 1210)
+ {
+ maxw = 2550;
+ maxh = 3500;
+ }
+ else
+ {
+ maxw = 5100;
+ maxh = 7000;
+ }
+ if (width < 0)
+ width = maxw;
+ if (height < 0)
+ height = maxh;
+
+ if ((width < 1) || (width > maxw))
+ {
+ fprintf (stderr, "width must be between 1 and %d\n", maxw);
+ return 0;
+ }
+ if (x + width > maxw)
+ {
+ fprintf (stderr,
+ "Right side of scan area exceed physical limits (x+witdh>%d)\n",
+ maxw);
+ return 0;
+ }
+ if (y < 0 || y > maxh)
+ {
+ fprintf (stderr, "y must be between 0 and %d\n", maxh - 1);
+ return 0;
+ }
+ if (x < 0 || x > maxw)
+ {
+ fprintf (stderr, "x must be between 0 and %d\n", maxw - 1);
+ return 0;
+ }
+ if ((height < 1) || (height > maxh))
+ {
+ fprintf (stderr, "height must be between 1 and %d\n", maxh);
+ return 0;
+ }
+ if (y + height > maxh)
+ {
+ fprintf (stderr,
+ "Bottom side of scan area exceed physical limits (y+height>%d)\n",
+ maxh);
+ return 0;
+ }
+
+ /* init transport layer */
+ /* 0: failed
+ 1: success
+ 2: retry
+ */
+ do
+ {
+ i = sanei_umax_pp_initTransport (recover);
+ }
+ while (i == 2);
+ if (i != 1)
+ {
+ printf ("initTransport() failed (%s:%d)\n", __FILE__, __LINE__);
+ return 0;
+ }
+ /* init scanner */
+ if (sanei_umax_pp_initScanner (recover) == 0)
+ {
+ sanei_umax_pp_endSession ();
+ return 0;
+ }
+
+ /* set x origin left to right */
+ x = sanei_umax_pp_getLeft () + (maxw - x) - width;
+
+ /* scan */
+ if (sanei_umax_pp_scan
+ (x, y, width, height, dpi, color, gain, offset) != 1)
+ {
+ sanei_umax_pp_endSession ();
+ return 0;
+ }
+
+ /* wait for head parking */
+ sanei_umax_pp_parkWait ();
+ printf ("Done ....\n");
+ }
+ sanei_umax_pp_endSession ();
+#ifdef HAVE_LINUX_PPDEV_H
+ fd = sanei_umax_pp_getparport ();
+ if (fd > 0)
+ {
+ close (fd);
+ sanei_umax_pp_setparport (0);
+ }
+#endif
+
+ return 1;
+}
diff --git a/tools/xerox b/tools/xerox
new file mode 100755
index 0000000..0b2a7c3
--- /dev/null
+++ b/tools/xerox
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# This is a xerox script for Laserjet Printer.
+# To get use of Postscript change the Printercommand and enable the
+# command at the end of this File.
+#
+DEV=mustek:/dev/scanner
+RES=300
+PAPERTYPE=letter
+#PAPERTYPE=a4
+PRINTERTYPE=ps
+#PRINTERTYPE=lj
+#
+# Non-printable area (left, right, top, and bottom margins):
+#
+LMARGIN=0.0
+RMARGIN=0.0
+TMARGIN=0.25
+BMARGIN=0.0
+#
+# Scanner-specific options:
+#
+DEVOPTS="--mode Gray"
+#DEVOPTS="$DEVOPTS --custom-gamma=yes --gamma-table [0]0-[64]128-[255]255"
+#DEVOPTS="$DEVOPTS --backtrack=yes" # needed for Mustek 12000SP
+#
+# Printer Command/Resolution
+PRES=$RES # change this if other Res. is desired
+#
+# Papersize in inch
+if [ "$PAPERTYPE" = "letter" ]; then
+ WIDTH=8; HEIGHT=10
+else
+ # assume a4 paper
+ WIDTH=8.27; HEIGHT=11.69
+fi
+
+SCANWIDTH=`bc <<_EOF_
+scale=3
+$WIDTH-$LMARGIN-$RMARGIN
+_EOF_`
+SCANHEIGHT=`bc <<_EOF_
+scale=3
+$HEIGHT-$TMARGIN-$BMARGIN
+_EOF_`
+#
+SCALE=`bc << _EOF_
+scale=3
+75/$RES
+_EOF_`
+
+if [ "$PRINTERTYPE" = "ps" ]; then
+ POST="pnmtops -rle -scale $SCALE -dpi $PRES | lpr"
+else
+ POST="pgmtopbm | pbmtolj -resolution $PRES | lpr -Praw"
+fi
+
+scanimage -d $DEV \
+ -x $SCANWIDTH\" -y $SCANHEIGHT\" -l $LMARGIN\" -t $TMARGIN\" \
+ --resolution $RES $DEVOPTS | eval $POST