[PATCHv2] mpi2*: add support for udev's hwdb

Tom Gundersen teg at jklm.no
Fri Jul 19 06:40:46 PDT 2013


udev recently gained a hardware database that is intended to replace large
udev rule files such as the one shipped with media-player-info. This should
give a significant (>50%) speed-up in the processing of usb add events.

This patch adds support for converting mpi to hwdb (where applicable), and
restricts the mpi2udev tool to only output the entries that cannot be
represented in the hwdb format.

Sample udev file: <https://dev.archlinux.org/~tomegun/40-usb-media-players.rules>
Sample hwdb file: <https://dev.archlinux.org/~tomegun/20-usb-media-players.hwdb>

Similar patches were recently submitted to
  gphoto2: <http://sourceforge.net/mailarchive/forum.php?thread_name=CAG-2HqVsNezxM9vh17uiTPQob4S0fWxoVmW%2BCO_iUzmM6SkiHw%40mail.gmail.com&forum_name=gphoto-devel>.
  sane: <http://lists.alioth.debian.org/pipermail/sane-devel/2013-July/031491.html>.

---
v2: hook into build system
    make hwdb support conditional upon a recent enough udev version
    fix detection for when a rule cannot be represented in hwdb format
    make python scripts deal with /usr/bin/python pointing to python3

 configure.ac               |  2 ++
 media-players/Makefile.am  | 10 ++++--
 tools/Makefile.am          |  2 +-
 tools/mpi2hwdb.py          | 83 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/mpi2udev.py          | 57 +++++++++++++++++++++----------
 tools/udev-syntax-check.py |  2 +-
 6 files changed, 134 insertions(+), 22 deletions(-)
 create mode 100755 tools/mpi2hwdb.py

diff --git a/configure.ac b/configure.ac
index a0db0b0..7cbcd57 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,6 +11,8 @@ if test "${ac_with_udevdir}" = ""; then
 	ac_with_udevdir=`$PKG_CONFIG --variable=udevdir udev`
 fi
 
+AC_SUBST([UDEV_VER],[`$PKG_CONFIG --modversion udev`])
+
 AC_MSG_NOTICE([installing udev rules in ${ac_with_udevdir}/rules.d])
 AC_SUBST([UDEV_DIR],[${ac_with_udevdir}])
 
diff --git a/media-players/Makefile.am b/media-players/Makefile.am
index 140ab97..1d59f7f 100644
--- a/media-players/Makefile.am
+++ b/media-players/Makefile.am
@@ -4,9 +4,15 @@ dist_mpi_DATA =  $(shell find $(top_srcdir)/media-players -name "*.mpi" -printf
 udevrulesdir = $(UDEV_DIR)/rules.d
 dist_udevrules_DATA = 40-usb-media-players.rules
 40-usb-media-players.rules: $(dist_mpi_DATA) $(top_srcdir)/tools/mpi2udev.py
-	$(top_srcdir)/tools/mpi2udev.py $(dist_mpi_DATA) > 40-usb-media-players.rules
+	$(top_srcdir)/tools/mpi2udev.py $(UDEV_VER) $(dist_mpi_DATA) > 40-usb-media-players.rules
 	$(top_srcdir)/tools/udev-syntax-check.py 40-usb-media-players.rules
 
+udevhwdbdir = $(UDEV_DIR)/hwdb.d
+dist_udevhwdb_DATA = 20-usb-media-players.hwdb
+20-usb-media-players.hwdb: $(dist_mpi_DATA) $(top_srcdir)/tools/mpi2hwdb.py
+	$(top_srcdir)/tools/mpi2hwdb.py $(dist_mpi_DATA) > 20-usb-media-players.hwdb
+
 clean-local:
 	-rm -f 40-usb-media-players.rules
-EXTRA_DIST = 40-usb-media-players.rules
+	-rm -f 20-usb-media-players.hwdb
+EXTRA_DIST = 40-usb-media-players.rules 20-usb-media-players.hwdb
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 35f9744..a29bd80 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1 +1 @@
-EXTRA_DIST = COPYING fdi2mpi.py mpi2udev.py udev-syntax-check.py
+EXTRA_DIST = COPYING fdi2mpi.py mpi2udev.py mpi2hwdb.py udev-syntax-check.py
diff --git a/tools/mpi2hwdb.py b/tools/mpi2hwdb.py
new file mode 100755
index 0000000..ea73ff6
--- /dev/null
+++ b/tools/mpi2hwdb.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python2
+# Generate hwdb file from music player identification (.mpi) files
+#
+# (C) 2009 Canonical Ltd.
+# Author: Martin Pitt <martin.pitt at ubuntu.com>
+# (C) 2013 Tom Gundersen <teg at jklm.no>
+#
+# 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.
+
+import sys, ConfigParser, os.path
+
+def parse_mpi(mpi):
+    '''Print hwdb file for given ConfigParser object.'''
+
+    cp = ConfigParser.RawConfigParser()
+    assert cp.read(mpi)
+
+    # if we have more info than just idVendor+idProduct we need to use an udev rule,
+    # so don't write an hwdb entry
+    for name in ['usbvendor', 'usbproduct', 'usbmodel', 'usbmanufacturer']:
+        try:
+            cp.get('Device', name)
+            return
+        except ConfigParser.NoOptionError:
+            continue
+
+    try:
+        m = cp.get('Device', 'product')
+        print '#', m
+    except ConfigParser.NoOptionError:
+        pass
+
+    try:
+        usbids = {}
+        for usbid in cp.get('Device', 'devicematch').split(';'):
+            if len(usbid.split(':')) != 3:
+                continue
+            (subsystem, vid, pid) = usbid.split(':')
+            if subsystem != "usb":
+                continue
+            if usbids.has_key(vid):
+                usbids[vid].append(pid)
+            else:
+                usbids[vid] = [ pid ]
+
+        for vid, pids in usbids.iteritems():
+		for pid in pids:
+	            print 'usb:v%sp%s*\n'% (vid.upper(), pid.upper()),
+	            print ' ID_MEDIA_PLAYER=%s\n' % os.path.splitext(os.path.basename(mpi))[0],
+
+                    # do we have an icon?
+                    try:
+                        icon = cp.get('Device', 'icon')
+                        # breaks media player detection : https://bugs.launchpad.net/ubuntu/+source/gvfs/+bug/657609
+                        #print ' UDISKS_PRESENTATION_ICON_NAME=%s\n' % icon,
+                    except ConfigParser.NoOptionError:
+                        pass
+
+                    # terminate line
+                    print
+
+    except ConfigParser.NoOptionError:
+        pass
+
+#
+# main
+#
+
+# parse MPI files
+for f in sys.argv[1:]:
+    parse_mpi(f)
diff --git a/tools/mpi2udev.py b/tools/mpi2udev.py
index fa89c2c..b17ab63 100755
--- a/tools/mpi2udev.py
+++ b/tools/mpi2udev.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python2
 # Generate udev rules from music player identification (.mpi) files
 #
 # (C) 2009 Canonical Ltd.
@@ -30,24 +30,27 @@ mpi2udev = {
     'usbmanufacturer': 'ATTRS{manufacturer}=="%s"',
 }
 
-def parse_mpi(mpi):
+def parse_mpi(mpi, hwdb):
     '''Print udev rule for given ConfigParser object.'''
 
     cp = ConfigParser.RawConfigParser()
     assert cp.read(mpi)
 
-    try:
-        m = cp.get('Device', 'product')
-        print '#', m
-    except ConfigParser.NoOptionError:
-        pass
+    rule = ''
+
     for name in ['usbvendor', 'usbproduct', 'usbmodel', 'usbmanufacturer']:
         try:
             value = cp.get('Device', name)
-            print mpi2udev[name] % value, ',',
+            rule += mpi2udev[name] % value + ', '
         except ConfigParser.NoOptionError:
             continue
 
+
+    # if using hwdb and no info other than idVendor+idProduct was found, we don't need to write
+    # an udev rule
+    if hwdb and not rule:
+        return
+
     try:
         usbids = {}
         for usbid in cp.get('Device', 'devicematch').split(';'):
@@ -62,22 +65,32 @@ def parse_mpi(mpi):
                 usbids[vid] = [ pid ]
 
         for vid, pids in usbids.iteritems():
-            print 'ATTRS{idVendor}=="%s" , ATTRS{idProduct}=="%s"'% (vid, '|'.join(pids)), ',',
-            print 'ENV{ID_MEDIA_PLAYER}="%s"' % os.path.splitext(os.path.basename(mpi))[0],
+            rule += 'ATTRS{idVendor}=="%s", ATTRS{idProduct}=="%s"'% (vid, '|'.join(pids)) + ', '
+    except ConfigParser.NoOptionError:
+        pass
+
+    # if no information was found, don't write a rule at all
+    if not rule:
+        return
 
+    try:
+        m = cp.get('Device', 'product')
+        print '#', m
     except ConfigParser.NoOptionError:
-        print 'ENV{ID_MEDIA_PLAYER}="%s"' % os.path.splitext(os.path.basename(mpi))[0],
+        pass
+
+    rule += 'ENV{ID_MEDIA_PLAYER}="%s"' % os.path.splitext(os.path.basename(mpi))[0]
 
     # do we have an icon?
     try:
         icon = cp.get('Device', 'icon')
         # breaks media player detection : https://bugs.launchpad.net/ubuntu/+source/gvfs/+bug/657609
-        # print ', ENV{UDISKS_PRESENTATION_ICON_NAME}="%s"' % icon,
+        # rule += ', ENV{UDISKS_PRESENTATION_ICON_NAME}="%s"' % icon
     except ConfigParser.NoOptionError:
         pass
 
-    # terminate rule line
-    print
+    # print out the rule
+    print rule + '\n'
 
 #
 # main
@@ -90,15 +103,23 @@ ENV{DEVTYPE}=="usb_device", GOTO="media_player_start"
 
 # catch UMS devices
 SUBSYSTEM!="block", GOTO="media_player_end"
-SUBSYSTEMS=="usb", GOTO="media_player_start"
-GOTO="media_player_end"
+SUBSYSTEMS!="usb", GOTO="media_player_end"
 
 LABEL="media_player_start"
 '''
 
+# the first argument should be the udev version
+# if it is not we fall back to the old behaviour
+try:
+    hwdb = int(sys.argv[1]) >= 196
+    mpis = sys.argv[2:]
+except ValueError:
+    hwdb = 0
+    mpis = sys.argv[1:]
+
 # parse MPI files
-for f in sys.argv[1:]:
-    parse_mpi(f)
+for f in mpis:
+    parse_mpi(f, hwdb)
 
 # udev rules footer
 print '\nLABEL="media_player_end"'
diff --git a/tools/udev-syntax-check.py b/tools/udev-syntax-check.py
index 8f949fa..89739c9 100755
--- a/tools/udev-syntax-check.py
+++ b/tools/udev-syntax-check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python2
 # Simple udev rules syntax checker
 #
 # (C) 2010 Canonical Ltd.
-- 
1.8.3.3



More information about the devkit-devel mailing list