diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile.am | 79 | ||||
-rw-r--r-- | tools/Makefile.in | 916 | ||||
-rw-r--r-- | tools/README | 74 | ||||
-rw-r--r-- | tools/RenSaneDlls.cmd | 33 | ||||
-rwxr-xr-x | tools/check-po.awk | 173 | ||||
-rw-r--r-- | tools/check-usb-chip.c | 4128 | ||||
-rw-r--r-- | tools/gamma4scanimage.c | 140 | ||||
-rw-r--r-- | tools/hotplug-ng/README | 46 | ||||
-rwxr-xr-x | tools/hotplug-ng/libsane.hotplug | 29 | ||||
-rw-r--r-- | tools/hotplug/README | 35 | ||||
-rwxr-xr-x | tools/hotplug/libusbscanner | 35 | ||||
-rwxr-xr-x | tools/libtool-get-dll-ext | 19 | ||||
-rw-r--r-- | tools/mustek600iin-off.c | 199 | ||||
-rwxr-xr-x | tools/openbsd/attach | 20 | ||||
-rwxr-xr-x | tools/openbsd/detach | 22 | ||||
-rw-r--r-- | tools/sane-backends.pc.in | 14 | ||||
-rw-r--r-- | tools/sane-config.in | 91 | ||||
-rw-r--r-- | tools/sane-desc.c | 4056 | ||||
-rw-r--r-- | tools/sane-find-scanner.c | 2100 | ||||
-rw-r--r-- | tools/umax_pp.c | 573 | ||||
-rwxr-xr-x | tools/xerox | 60 |
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 *) ®, 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 *) ®, 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, ®, 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, "<"); + break; + case '>': + aux = strcat (aux, ">"); + break; + case '\'': + aux = strcat (aux, "'"); + break; + case '&': + aux = strcat (aux, "&"); + 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> </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> </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> </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> </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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 (¤t_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 |