diff --git a/create_sane-backends-autoconfig.rules b/create_sane-backends-autoconfig.rules new file mode 100644 index 0000000..179204e --- /dev/null +++ b/create_sane-backends-autoconfig.rules @@ -0,0 +1,112 @@ +#! /bin/bash +# +# Johannes Meixner , 2004, 2005, 2006 + +#set -x + +export PATH="/sbin:/usr/sbin:/usr/bin:/bin" +export LC_ALL="POSIX" +export LANG="POSIX" +umask 022 + +MY_NAME=${0##*/} + +# Input: + +# Create a temporary file: +TMP_DATA=$(mktemp /tmp/$MY_NAME.XXXXXX) || { echo "Error: Failed to make a temporary file /tmp/$MY_NAME.XXXXXX" 1>&2 ; exit 1 ; } + +# Extract only those USB scanners +# which are supported by the packages "sane-backends", "iscan-free", or "hplip" +# (i.e. not by the proprietary 32-bit-only i386-only "iscan" package) +# and where the USB-ID is known +# and which do not require firmware upload (i.e. FIRMWARE field is empty) +# and where the support status is "complete" or "good" (i.e. skip "basic", "minimal", "untested", "unsupported") +# and keep only the fields of interest (i.e. BACKEND and USBID) +# and keep only unique lines (there are many duplicates among the fields of interest) +# and sort according to the USB-ID to have different driver lines for the same model contiguous +# which is needed to choose only one driver which is automatically activated +# because otherwise a scanner will show up multiple times in scanning frontends +# (once for each activated driver which works for this model) +# and finally set the usual input field separator ' ' (there are no blanks in BACKEND or USB-ID): +bash create_scanner_database ASCII | egrep '^sane-backends|^iscan-free|^hplip' | grep '||USB|0x[0-9A-Fa-f][0-9A-Fa-f]*:0x[0-9A-Fa-f][0-9A-Fa-f]*|' | cut -s -d '|' -f 2,7,8 | egrep 'complete$|good$' | cut -s -d '|' -f 1,2 | sort -u | sort -t '|' -k 2 | tr '|' ' ' >$TMP_DATA + +# Output: + +# Output header: +echo 'ACTION!="add", GOTO="sane_backends_autoconfig_rules_end"' +echo + +# Output the scanner model entries: +USED_BACKENDS="" +PREVIOUS_VENDOR="" +PREVIOUS_MODEL="" +BACKENDS_FOR_SAME_MODEL="" +# Append a dummy entry to trigger the output for the last real model in the while loop: +echo 'dummy 0x0000:0x0000' >>$TMP_DATA +exec <$TMP_DATA +while read BACKEND USBID +do [ -z "$BACKEND" ] && { echo "Ignoring $USBID because there is no driver entry." 1>&2 ; continue ; } + VENDOR=$( echo $USBID | cut -s -d ':' -f 1 | sed -e 's/^0x//' ) + [ -z "$VENDOR" ] && { echo "Ignoring $USBID because there is no vendor ID." 1>&2 ; continue ; } + MODEL=$( echo $USBID | cut -s -d ':' -f 2 | sed -e 's/^0x//' ) + [ -z "$MODEL" ] && { echo "Ignoring $USBID because there is no model ID." 1>&2 ; continue ; } + # If the current model is the same as the previous model, + # add only the current backend to the list of backends for the same model: + if [ "$VENDOR" = "$PREVIOUS_VENDOR" -a "$MODEL" = "$PREVIOUS_MODEL" ] + then BACKENDS_FOR_SAME_MODEL=$( echo "$BACKENDS_FOR_SAME_MODEL $BACKEND" ) + continue + fi + # When the model has changed, + # determine the "best" backend for the previous model + # and output only one single entry for it. + # Currently different driver lines for the same model happen only + # for Epson scanners (USB vendor ID 0x04b8): + # Many models are supported by epkowa, epson2, and epson (unmaintained driver). + # Two models are supported by plustek (and the non-free epkowa version in "iscan") + # One model is supported by epson2 and epson. + # The preferred driver is epkowa because + # it supports more models than the other drivers, + # it is made by the manufacturer (via Epson Avasys), and + # it is free software in the iscan-free package ("iscan" is suppressed, see above). + # On the one hand this means that when the iscan-free package is not installed, + # those scanners would not be autoconfigured even if many of those scanners are also + # supported by the epson2 driver (which is not activated because epkowa is preferred). + # On the other hand this avoids that different drivers are activated for the same model + # which lets the model show up several times in the scanning frontend (once for each driver). + # For example imagine there are two Epson USB scanners connected: + # One is supported only by epkowa, the other one is supported by epkowa and epson2. + # If both epkowa and epson2 would be activated, the other one would show up twice. + # Furthermore epson2 is preferred over the meanwhile unmaintained epson driver. + BEST_BACKEND="" + for B in plustek epson epson2 epkowa + do echo $BACKENDS_FOR_SAME_MODEL | grep -q "$B" && BEST_BACKEND="$B" + done + # Do not use 'cut -s' because BACKENDS_FOR_SAME_MODEL contains usually only one entry: + [ -z "$BEST_BACKEND" ] && BEST_BACKEND=$( echo $BACKENDS_FOR_SAME_MODEL | cut -d ' ' -f 1 ) + if [ -n "$BEST_BACKEND" ] + then USED_BACKENDS=$( echo "$USED_BACKENDS $BEST_BACKEND" ) + echo "SYSFS{idVendor}==\"$PREVIOUS_VENDOR\", SYSFS{idProduct}==\"$PREVIOUS_MODEL\", ENV{sane_backend_$BEST_BACKEND}=\"yes\"" + fi + # Remember the current model: + BACKENDS_FOR_SAME_MODEL="$BACKEND" + PREVIOUS_VENDOR="$VENDOR" + PREVIOUS_MODEL="$MODEL" +done + +echo + +# Output the driver activation lines: +for B in $( echo $USED_BACKENDS | tr ' ' '\n' | sort -u ) +do echo "ENV{sane_backend_$B}==\"yes\", RUN+=\"/bin/sed -i -e 's/^[[:space:]]*#[[:space:]]*$B[[:space:]]*\$/$B/' /etc/sane.d/dll.conf\"" +done +echo + +# Output footer: +echo 'LABEL="sane_backends_autoconfig_rules_end"' +echo + +# Remove the temporary file +rm $TMP_DATA +exit 0 + diff --git a/create_scanner_database b/create_scanner_database new file mode 100644 index 0000000..c656e8a --- /dev/null +++ b/create_scanner_database @@ -0,0 +1,183 @@ +#! /bin/bash +# +# Johannes Meixner , 2004, 2005, 2006 + +#set -x + +export PATH="/sbin:/usr/sbin:/usr/bin:/bin" +export LC_ALL="POSIX" +export LANG="POSIX" +umask 022 + +MY_NAME=${0##*/} +OUTPUT_FORMAT="$1" +[ -z "$OUTPUT_FORMAT" ] && OUTPUT_FORMAT="ASCII" +[ "$OUTPUT_FORMAT" != "ASCII" -a "$OUTPUT_FORMAT" != "YCP" ] && { echo -en "\nUsage:\n$MY_NAME {ASCII|YCP}\n" 1>&2 ; exit 1 ; } + +# Input: + +# Create a temporary file: +TMP_DATA=$(mktemp -u /tmp/$MY_NAME.XXXXXX) +cat /dev/null >$TMP_DATA + +# Function to extract entries from a description file with SANE syntax. +# Quoted quotation marks '\"' (happens in comments) are replaced by ' ': +Extract() +{ cat $1 | sed -e 's/\\"/ /g' | egrep -o '^[[:space:]]*:backend[[:space:]]*"[^"]*"|^[[:space:]]*:mfg[[:space:]]*"[^"]*"|^[[:space:]]*:model[[:space:]]*"[^"]*"|^[[:space:]]*:firmware[[:space:]]*"[^"]*"|^[[:space:]]*:interface[[:space:]]*"[^"]*"|^[[:space:]]*:usbid[[:space:]]*"0x[0-9A-Fa-f]*"[[:space:]]*"0x[0-9A-Fa-f]*"|^[[:space:]]*:status[[:space:]]*:[a-z]*|^[[:space:]]*:comment[[:space:]]*"[^"]*"' +} + +# Process the SANE description files: +# At least the SANE description files must exist: +PACKAGE="sane-backends" +DESCRIPTION_FILES="/usr/share/sane/descriptions/*.desc" +ls $DESCRIPTION_FILES &>/dev/null || { echo "Error: Required SANE description files $DESCRIPTION_FILES not found." 1>&2 ; exit 3 ; } +# Write the package which is processed: +echo ":package \"$PACKAGE\"" >>$TMP_DATA +# Extract entries from SANE description files: +for DESCRIPTION_FILE in $DESCRIPTION_FILES +do Extract $DESCRIPTION_FILE +done >>$TMP_DATA + +# Process the optional HPLIP external description file: +# The package hplip is installed by default. +PACKAGE="hplip" +DESCRIPTION_FILE="/usr/share/sane/descriptions-external/hpaio.desc" +if [ -r "$DESCRIPTION_FILE" ] +then echo ":package \"$PACKAGE\"" >>$TMP_DATA + Extract $DESCRIPTION_FILE >>$TMP_DATA +else echo "Info: Cannot read $DESCRIPTION_FILE" 1>&2 +fi + +# Process the optional EPSON AVASYS (formerly EPSON KOWA) Image Scan external description file: +# The proprietary binary-only i386-only package iscan cannot be installed by default. +# The package iscan-free is not installed by default. +PACKAGE="iscan" +DESCRIPTION_FILE="/usr/share/sane/descriptions-external/epkowa.desc" +if [ -r "$DESCRIPTION_FILE" ] +then echo ":package \"$PACKAGE\"" >>$TMP_DATA + Extract $DESCRIPTION_FILE >>$TMP_DATA +else echo "Info: Cannot read $DESCRIPTION_FILE" 1>&2 +fi + +# Process the collected data: + +# Replace HTML tags: +sed -i -e 's/<[Bb][Rr]>/, /g' \ + -e 's/<[Pp]>/, /g' \ + -e 's/<[^>]*>/ /g' $TMP_DATA + +# Condense multiple spaces and convert tabs to blanks: +sed -i -e 's/[[:space:]][[:space:]]*/ /g' $TMP_DATA + +# Remove leading and trailing spaces: +sed -i -e 's/^[[:space:]]*//' \ + -e 's/[[:space:]]*$//' \ + -e 's/"[[:space:]]*/"/g' \ + -e 's/[[:space:]]*"$/"/' $TMP_DATA + +# Convert the usbid values from '"vendor-id""product-id"' to '"vendor-id:product-id"' +# (note that '" "' was changed to '""' in the step before): +sed -i -e '/^:usbid/s/""/:/' $TMP_DATA + +# Convert the status value to the usual string format: +sed -i -e 's/^:status :\(.*\)/:status "\1"/' $TMP_DATA + +# Equalize different spelling of same manufacturers: +sed -i -e 's/"AGFA"/"Agfa"/g' \ + -e 's/"UMAX"/"Umax"/g' $TMP_DATA + +# Change meaningless references to a meaningful reference: +sed -i -e 's/see link/see http:\/\/www.sane-project.org/g' \ + -e 's/See link/See http:\/\/www.sane-project.org/g' $TMP_DATA + +# Output: + +# Output header: +if [ "$OUTPUT_FORMAT" = "YCP" ] +then echo "[" +else echo "PACKAGE|BACKEND|MANUFACTURER|MODEL|FIRMWARE|INTERFACE|USBID|STATUS|COMMENT" +fi + +# Function to output one scanner entry: +Output() +{ if [ -n "$PACKAGE" -a -n "$BACKEND" -a -n "$MANUFACTURER" -a -n "$MODEL" -a -n "$STATUS" ] + then [ -z "$FIRMWARE" ] && FIRMWARE='""' + [ -z "$INTERFACE" ] && INTERFACE='""' + [ -z "$USBID" ] && USBID='""' + [ -z "$COMMENT" ] && COMMENT='""' + if [ "$PACKAGE" = '"iscan"' -o "$PACKAGE" = '"iscan-free"' ] + then if echo "$COMMENT" | egrep -q 'requires a DFSG non-free module|requires DFSG non-free' + then PACKAGE='"iscan"' + else PACKAGE='"iscan-free"' + fi + fi + if [ "$OUTPUT_FORMAT" = "YCP" ] + then echo -e " \$[ \"package\":$PACKAGE,\n \"backend\":$BACKEND,\n \"manufacturer\":$MANUFACTURER,\n \"model\":$MODEL,\n \"firmware\":$FIRMWARE,\n \"interface\":$INTERFACE,\n \"usbid\":$USBID,\n \"status\":$STATUS,\n \"comment\":$COMMENT\n ]," + else echo "$PACKAGE|$BACKEND|$MANUFACTURER|$MODEL|$FIRMWARE|$INTERFACE|$USBID|$STATUS|$COMMENT" | tr -d '"' + fi + fi +} + +# Make complete and seperated scanner entries: +# Package, backend, manufacturer and model should appear in this order. +# Interface, status and comment are optional and can appear in any order. +# There is no mandatory key which is always last. +# Therefore the values are collected until package or backend or manufacturer or model changes. +# When package or backend or manufacturer or model changes the values are output. +exec <$TMP_DATA +while read KEY VALUE +do expr "$VALUE" : '"[^"]*"$' &>/dev/null || { echo "Ignoring $VALUE because it has not the right syntax \"...\"." 1>&2 ; continue ; } + case "$KEY" in + :package) Output + PACKAGE="$VALUE" + BACKEND="" + MANUFACTURER="" + MODEL="" + FIRMWARE="" + INTERFACE="" + USBID="" + STATUS="" + COMMENT="" ;; + :backend) Output + BACKEND=$( echo "$VALUE" | tr '[:upper:]' '[:lower:]' ) + MANUFACTURER="" + MODEL="" + FIRMWARE="" + INTERFACE="" + USBID="" + STATUS="" + COMMENT="" ;; + :mfg) Output + MANUFACTURER="$VALUE" + MODEL="" + FIRMWARE="" + INTERFACE="" + USBID="" + STATUS="" + COMMENT="" ;; + :model) Output + MODEL="$VALUE" + FIRMWARE="" + INTERFACE="" + USBID="" + STATUS="" + COMMENT="" ;; + :firmware) FIRMWARE="$VALUE" ;; + :interface) INTERFACE="$VALUE" ;; + :usbid) USBID=$( echo "$VALUE" | tr '[:upper:]' '[:lower:]' ) ;; + :status) STATUS="$VALUE" ;; + :comment) COMMENT="$VALUE" ;; + *) echo "Ignoring key $KEY" 1>&2 ;; + esac +done + +# Output the last scanner entry and a footer for YCP +Output +if [ "$OUTPUT_FORMAT" = "YCP" ] +then echo -e " \$[]\n]" +fi + +# Remove the temporary file +rm $TMP_DATA +exit 0 + diff --git a/sane-backends.changes b/sane-backends.changes index 97056e8..3f83036 100644 --- a/sane-backends.changes +++ b/sane-backends.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Thu Mar 13 14:00:15 CET 2008 - jsmeix@suse.de + +- Added "scanner autoconfiguration" support via + create_scanner_database, create_sane-backends-autoconfig.rules + which create /etc/udev/rules.d/56-sane-backends-autoconfig.rules + and provide it in the new sane-backends-autoconfig sub-package + (see Novell/Suse Bugzilla bnc#347943). + ------------------------------------------------------------------- Tue Mar 11 15:30:25 CET 2008 - jsmeix@suse.de diff --git a/sane-backends.spec b/sane-backends.spec index 637623b..74f78d9 100644 --- a/sane-backends.spec +++ b/sane-backends.spec @@ -18,7 +18,7 @@ Group: Hardware/Scanner AutoReqProv: on Summary: SANE (Scanner Access Now Easy) Scanner Drivers Version: 1.0.19 -Release: 8 +Release: 10 Url: http://www.sane-project.org/ # URL for Source0: http://alioth.debian.org/frs/download.php/2318/sane-backends-1.0.19.tar.gz Source0: sane-backends-%{version}.tar.bz2 @@ -59,6 +59,18 @@ Source105: epkowa.desc # Source107 is obsolete since sane-backends-1.0.19 because it has udev and HAL support. # Source108 is a script which outputs a HAL fdi file. # Source108 is obsolete since sane-backends-1.0.19 because it has udev and HAL support. +# Source200... is scanner autoconfiguration stuff: +# Source200 and Source201 generate the 56-sane-backends-autoconfig.rules file +# for automated scanner driver activation via udev ("scanner autoconfiguration"). +# Source200 is a copy of /usr/lib/YaST2/bin/create_scanner_database +# to avoid yast2-scanner in BuildRequires which would drag almost the whole YaST: +Source200: create_scanner_database +# Source201 actually generates the 56-sane-backends-autoconfig.rules file +# by calling create_scanner_database which reads the description files +# to extract the needed info from which create_sane-backends-autoconfig.rules +# generates the 56-sane-backends-autoconfig.rules file: +Source201: create_sane-backends-autoconfig.rules +# based upon the data which is # Patch1 does locale rename: no -> nb: # Patch1 is obsolete since sane-backends-1.0.19 because it uses 'nb'. # Patch2 fixes too small arrays in backend/niash.c: @@ -214,6 +226,47 @@ Authors: Ulrich Deiters Wittawat Yamwong +%package autoconfig +Group: Hardware/Scanner +Summary: USB Scanner Autoconfiguration +Requires: sane-backends + +%description autoconfig +USB scanner autoconfiguration happens via udev. + +The file /etc/udev/rules.d/56-sane-backends-autoconfig.rules contains +entries for those USB scanners where the USB IDs are known, which are +supported by a free driver, where the support status is "complete" or +"good", and which do not require firmware upload. + +When a USB scanner is connected and its USB IDs match to an entry in +the 56-sane-backends-autoconfig.rules file, the matching scanner driver +is activated (i.e. the driver line in /etc/sane.d/dll.conf is +activated). + +It enables scanner drivers but never disables them. The reason is that +enabled drivers do not hurt so that an automated disable would make it +only overcomplicated because when more than one scanner uses the same +driver, a complicated check would be needed to avoid that the driver is +accidentally disabled when only one scanner was disconnected. + +Note that driver activation alone is not sufficient to have a usable +"scanner autoconfiguration" for the user. What is also needed are +appropriate USB device file permissions so that the user's scanning +software can access the device. But this is already in place via the +HAL 70-scanner.fdi file which triggers the resmgr to grant access +permissions for the user who is currently locally logged in (i.e. who +works directly at the computer where the USB scanner is). + +If you do not like automated driver activation, do not install this +package or remove it when it is already installed. + + + +Authors: +-------- + Johannes Meixner + %prep %setup -q # Patch2 fixes too small arrays in backend/niash.c: @@ -323,7 +376,7 @@ done # sane-teco2: mentiones only "firmware 1.09" (no firmware upload) # As far as we know all scanners which use # the backend gt68xx and the related backend artec_eplus48u -# or the backend sane-epjitsu require a firmware upload, +# or the backend epjitsu require a firmware upload, # see "man sane-gt68xx" and http://www.meier-geinitz.de/sane/gt68xx-backend/ # and see "man sane-artec_eplus48u" and "man sane-epjitsu" # @@ -402,6 +455,33 @@ install -m644 %{SOURCE101} %{buildroot}%{_sysconfdir}/xinetd.d/ # OpenSLP registration stuff: install -d -m755 %{buildroot}%{_sysconfdir}/slp.reg.d install -m644 %{SOURCE102} %{buildroot}%{_sysconfdir}/slp.reg.d +# Scanner autoconfiguration stuff (packaged in sane-backends-autoconfig): +# This requires the installed descriptions and descriptions-external files +# because create_sane-backends-autoconfig.rules calls create_scanner_database +# which reads the description files to extract the needed info from which +# it generates the 56-sane-backends-autoconfig.rules file +# for automated scanner driver activation via udev. +# Note that driver activation alone is not sufficient +# to have a usable "scanner autoconfiguration" for the user. +# What is also needed are appropriate USB device file permissions +# so that the user's scanning software can access the device. +# But this is already in place via the HAL 70-scanner.fdi file +# which contains a superset of USB scanner IDs (all known USB scanner IDs) +# compared to the USB scanner IDs in 56-sane-backends-autoconfig.rules, +# see create_sane-backends-autoconfig.rules for which USB scanners +# automated driver activation is done (basically only those scanners +# which are supported by a free driver, which do not require firmware upload, +# and where the support status is "complete" or "good"). +# Modify create_scanner_database to find the description files in the BuildRoot directory +# (the usual delimiter '/' cannot be used because buildroot contains it too): +sed -i -e 's|/usr/share/sane/descriptions|%{buildroot}/usr/share/sane/descriptions|' %{SOURCE200} +# Modify create_sane-backends-autoconfig.rules to call create_scanner_database with the right path +# (the usual delimiter '/' cannot be used because SOURCE200 contains it too): +sed -i -e 's|^bash create_scanner_database|bash %{SOURCE200}|' %{SOURCE201} +# Run it: +bash %{SOURCE201} >autoconfig.rules +# Install the scanner autoconfiguration udev rules file: +install -m644 autoconfig.rules %{buildroot}%{_sysconfdir}/udev/rules.d/56-sane-backends-autoconfig.rules %post /sbin/ldconfig @@ -445,7 +525,19 @@ exit 0 %doc %{_mandir}/man7/sane.7.gz %doc %{_mandir}/man8/saned.8.gz +%files autoconfig +%defattr(-,root,root) +%dir %{_sysconfdir}/udev +%dir %{_sysconfdir}/udev/rules.d +%{_sysconfdir}/udev/rules.d/56-sane-backends-autoconfig.rules + %changelog +* Thu Mar 13 2008 jsmeix@suse.de +- Added "scanner autoconfiguration" support via + create_scanner_database, create_sane-backends-autoconfig.rules + which create /etc/udev/rules.d/56-sane-backends-autoconfig.rules + and provide it in the new sane-backends-autoconfig sub-package + (see Novell/Suse Bugzilla bnc#347943). * Tue Mar 11 2008 jsmeix@suse.de - Replaced "scanner" by "SCSIviaUSBscanner" in info.capabilities in 70-scanner.fdi to explicitely mark those special USB scanners