Difference between revisions of "Device Filenames and udev"

From MythTV Official Wiki
Jump to: navigation, search
(More complicated setup with multi-tuner cards having no difference in udevadm info output coexisting with other cards based on the same A/V decoder)
m (changed shebang to bash)
(4 intermediate revisions by the same user not shown)
Line 179: Line 179:
 
== More complicated setup with multi-tuner cards having no difference in udevadm info output coexisting with other cards based on the same A/V decoder ==
 
== More complicated setup with multi-tuner cards having no difference in udevadm info output coexisting with other cards based on the same A/V decoder ==
  
It is possible that Your setup has many different cards and some of them have multiple tuners. If different cards have the same A/V decoder - relaying on udev might be tricky as reported Vendor/Device attributes might be the same for different cards (in such case usually A/V bridge attributes are reported). Also Manufacturer attributes are not always reported. In such case only solution is to use Subsystem_Vendor/Subsystem_ID attributes. Another issue might be related to case when udev reports exactly the same output for different tuners on the same card. In my case (Piotr Oniszczuk) udev solution based on rules presented above have issue with initialization races as each sub-device on DVB adapter (frontend, mux, dvr) are served separately so it is possible to receive adapterX with frontend from adapterY. Below is example of small tool able to deal with all above cases. To run it, launch "map-dvb-dapters.sh"
+
It is possible that Your setup has many different cards and some of them have multiple tuners. If different cards have the same A/V decoder - relaying on udev might be tricky as reported Vendor/Device attributes might be the same for different cards (in such case usually A/V bridge attributes are reported). Also Manufacturer attributes are not always reported. In such case only solution is to use Subsystem_Vendor/Subsystem_ID attributes. Another issue might be related to case when udev reports exactly the same output for different tuners on the same card. In my case (Piotr Oniszczuk) udev solution based on rules presented in this Wiki (p7) have issue with initialization races as each sub-device on DVB adapter (frontend, mux, dvr) are served separately so it is possible to receive adapterX with frontend from adapterY. Below is example of small tool able to deal with all above cases. To run it, launch "map-dvb-dapters.sh"
 
Script should be called with some delay as some drivers needs some time to finish initialization (firmware load, etc).
 
Script should be called with some delay as some drivers needs some time to finish initialization (firmware load, etc).
 
I'm using 5s delay.  
 
I'm using 5s delay.  
Line 256: Line 256:
 
    \
 
    \
 
    DvbSky_S952:%k \
 
    DvbSky_S952:%k \
    \
 
    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"
 
 
 
# Tevii S480 0xa000:0x4000
 
SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0", \
 
    \
 
    ATTRS{subsystem_vendor}=="0xa000", \
 
    ATTRS{subsystem_device}=="0x4000", \
 
    \
 
    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
 
    \
 
    Tevii_S480:%k \
 
 
    \
 
    \
 
    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"
 
    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"
Line 292: Line 279:
 
3. Create "map-dvb-adapters.sh" file and put this file into "/usr/local/bin/" dir.
 
3. Create "map-dvb-adapters.sh" file and put this file into "/usr/local/bin/" dir.
 
<pre>         
 
<pre>         
#!/bin/sh
+
#!/bin/bash
 
#
 
#
 
# map-dvb-adapters.sh file
 
# map-dvb-adapters.sh file
Line 367: Line 354:
  
 
echo "DVB adapters mapping utility v1.1"
 
echo "DVB adapters mapping utility v1.1"
echo "Copyright: Piotr Oniszczuk"
+
echo "Copyright: Piotr Oniszczuk, warpme-at-o2.pl"
  
  

Revision as of 17:23, 19 November 2012

Wikipedia-logo-en.png
Wikipedia has an article on:

MythTV often works well with the video devices it finds on your system using whatever default device assignments your distribution creates. Sometimes, though, problems arise. The most serious problem occurs when the association of a device filename (in the /dev directory tree) to a physical device is not persistent. This can happen with USB devices that are attached and detached at will, because of a need to use multiple kernels that are compiled in different ways, because of changes in your hardware configuration, or (so it seems sometimes) because of the phase of the Moon. If you're having problems keeping your video devices persistent, read on.


Important.png Note: This wiki entry describes configuring udev to create persistent device file entries. Most modern Linux distributions use udev; however, older distributions don't use udev. If your system doesn't use udev, this wiki entry won't do you any good. In such cases, you may be able to solve the problem by moving device drivers in or out of the kernel proper or by blacklisting them from being loaded automatically and then loading them manually in local startup scripts.

Basics of udev

The udev tool is a user-space filesystem that provides a dynamic mapping of device filenames (typically in /dev) to hardware devices. Developers created udev in order to overcome a number of limitations in previous Linux device file handling schemes, including the one that motivates this entry: inconsistency in device filename mappings to physical devices.

You can find udev configuration files in /etc/udev. The main configuration file is /etc/udev/udev.conf; however, you won't be touching this file. Instead, you'll be creating a new file in /etc/udev/rules.d. This directory holds files, often installed from multiple sources, each of which contains rules that tell udev how to create device files. The files in /etc/udev/rules.d typically take filenames of the form ##-*.rules, where ## is a 2-digit number and * is a name. For instance, on an Ubuntu 6.10 system, the udev rules files include 00-init.rules and 85-alsa.rules for the core rules and rules covering ALSA (audio) devices, respectively. The names of the rules files differ from one distribution to another, and even from one installation to another, depending on what packages you install.

The rules files consist of a series of rules, each of which contains key/value pairs, separated by commas. Each key may be either a matching key, which determines whether or not a rule is to be used, or an assignment key, which tells udev how to create a device file. Matching keys use == or != symbols to separate keys from values, indicating equality or inequality. Assignment keys use =, +=, or := symbols to assign a new value to a key, add a new value to an existing key, or assign a new value to a key while disallowing future changes, respectively. Be careful not to confuse the == and = operators!

As an example, consider the following line, which is taken from the 50-udev.rules file on a Gentoo system:

KERNEL=="video[0-9]*",  NAME="v4l/video%n", SYMLINK+="video%n", GROUP="video"

This line searches for a device that the kernel names video[0-9]* -- that is, video0, video1, and so on. (You can use wildcards, such as [0-9] and *, in much the same way as you can use wildcards when specifying filenames in a Linux shell.) Once found, the rule creates a device file with a name based on the kernel's internal name in the v4l subdirectory of /dev (NAME="v4l/video%n"), creates a symbolic link to this newly-created device file in the main /dev directory (SYMLINK+="video%n"), and assigns group ownership of the device file to the video group (GROUP="video"). Note that details of the default video device file creation differ from one distribution to another, so yours may not exactly match this example.

Many keys aside from these are available. You'll have to use some of these to create unique identifying device filenames; more on that later. Rather than create new device files proper, you'll probably find it convenient to create new symbolic links that point to the device files that are created automatically by udev.

You may want to take a few minutes to examine your existing udev rules files. You might want to try typing grep video /etc/udev/rules.d/* to find all the entries that relate to video devices. On distributions that employ a video account or group, you'll find entries that have nothing to do with video devices except that they're assigned to the video account or group, so you may have to sift through a lot of irrelevant matches. Take note of the sequence (leading 2-digit number) of the file that creates the video devices for future reference.

Obtaining identifying information

To uniquely identify your hardware, you must locate uniquely identifying information. This information could take the form of a device driver (if your devices use different drivers), a bus (PCI or USB, for instance), a model number, a serial number (if your devices have them), or perhaps other things. One good way to look for unique identifying information is to use udevadm to obtain information on the device:

udevadm info -a -p $(udevadm info -q path -n /dev/video0)

or for DVB-T devices

udevadm info -a -p $(udevadm info -q path -n /dev/dvb/adapter0/dvr0)

The result will be a rather lengthy list of udev matching key names and their associated values, for both the device you specify (/dev/video0 in this example) and all its parents. Issue this command for each of your devices in turn and search for unique key values. You'll probably want to restrict your search for unique key names to the first and second blocks of the udevadm output, which apply only to the device in question. (An exception might be if your two devices are on different busses, such as PCI and USB.) You can combine two or more identifying keys, if necessary. One common field to use in conjunction with another is the KERNEL key, which holds the kernel's identifying key for the device -- usually video0, video1 or something similar. You may want to use a wildcard to match the KERNEL identifier, since its number can change -- that's the source of the problem!


Information.png Tip: Try redirecting the output of udevadm to a file (by adding > ~/filename.txt to the command). If you redirect each output to a different file, you can use the diff command to compare them or load them both into text editors for side-by-side comparison.

Once you've located a uniquely identifying set of characteristics, you can proceed with configuring udev to recognize and act on those features.

Configuring udev

As an example, I've examined the udevadm info output for two video devices, a PcHDTV HD-3000 and a Hauppauge WinTV-PVR-USB2. The udevadm info output for the latter device was rather scant; however, I did find a uniquely identifying feature for the pcHDTV HD-3000, which is sufficient to proceed:

SYSFS{name}=="cx88_0_ video _pcHDTV HD3000 HD"

The SYSFS{name} key is present on the WinTV-PVR-USB2, but it's blank. Recent implementations use ATTR{} and ATTRS{} rather than SYSFS{}, but the principles are the same. Be sure to use whatever codes you see in your own rules. Using the unique key, a new pair of udev rules can be created:

KERNEL=="video[0-9]*", SYSFS{name}=="cx88*", SYMLINK+="video-pcHDTV"
KERNEL=="video[0-9]*", SYSFS{name}=="", SYMLINK+="video-PVR-USB2"

A few comments about these rules are in order:

  • The KERNEL=="video[0-9]*" key is required to keep the rules from matching non-video devices. The first rule might not be a big problem in this respect, but the second could be. You wouldn't want a printer or removable disk to get the video encoding device's filename!
  • The first rule truncates the name returned, using an asterisk (*) to match the remainder of the rule. A simple cut-and-paste doesn't work (presumably the spaces are confusing the system). Wildcards are useful in this case as well as when matching the KERNEL key.
  • The second rule matches a blank name. This happens to work for the PVR-USB2 with the 2.6.20 kernel drivers, but it might not work for other devices. If I were to add another encoder that has a blank name, I might need to add more rules or add the %n variable to the SYMLINK value to number these links.

A second example rule set is based on a system with a single video card, an AVerMedia M150-D. This card uses the Conexant 2388x chip and the 23416 MPEG-2 encoder chip, combined using the "Blackbird" reference design. As such, the card provides two video access files: one for accessing the card as a frame grabber and the second for accessing its MPEG-2 encoder. The design of the drivers is such that the MPEG-2 device file should generally be numbered above the framegrabber device file unless overridden in the module options; however, you might still want to provide more intuitive names to the device files or give constant names if you were using this device in conjunction with another. The following configuration does the trick:

KERNEL=="video[0-9]*", DRIVERS=="cx88-blackbird", SYMLINK+="video-M150-MPEG"
KERNEL=="video[0-9]*", DRIVERS=="cx8800", SYMLINK+="video-M150-framegrabber"

These rules look to the second block of output from udevadm info, using the DRIVERS key to differentiate the two devices.

Once you've created new udev rules, you should place them in a new udev rules file. You can include comment lines that begin with hash marks (#), if you like. Give the new file a name that begins with a number greater than the number of the file that creates the original video device files.


Important.png Note: Don't try to modify your existing udev rules files. These files are likely to be replaced by your distribution's packaging system when you upgrade your software. You can create rules for creating new links in a separate file, which shouldn't be touched by your distribution's packaging system.

Once this new rule file is in place, the symbolic links should be created the next time you load the relevant device drivers. These new links shouldn't change even if something happens to alter the original device filenames, such as if you add or remove hardware; however, check the Caveats section below for important exceptions! To test your new rule, you can either unload the video device drivers and add them back manually or reboot the computer.

You can use the same procedure to create rules for non-video devices. For instance, if you've got two sound cards to go with two framegrabber video cards, you can use this procedure to create uniquely-named audio device files. You would specify the audio device's filename in the udevadm info command to track down information that uniquely identifies each audio device.

Configuring MythTV

To use the new device files, you'll need to shut down your mythbackend process and use the mythtv-setup utility. You'll then use the Capture Cards option to edit your existing capture card configuration (or create a new one, if you've not yet configured this hardware). Chances are this tool won't be looking for the device files you've created, so you'll need to manually type the filenames in the relevant entry fields. Once this is done, though, mythtv-setup should correctly identify the device and enable you to save your changes.

Example HDPVR Rules file

Use udevadm to find the HDPVR serial number as documented above. This script creates /dev/v4l/hdpvr1 and /dev/v4l/hdpvr3 symlinks. Alter the serial number and symlink destination to your liking.

# /etc/udev/rules.d/10-hdpvr.rules
#HDPVR - hdpvr1
KERNEL=="video?",SUBSYSTEM=="video4linux",ATTRS{serial}=="00A4FCD7",
SYMLINK+="v4l/hdpvr1"

#HDPVR - hdpvr3
KERNEL=="video?",SUBSYSTEM=="video4linux",ATTRS{serial}=="00A4FC32",
SYMLINK+="v4l/hdpvr3"

Example DVB udev Rules file

The following is an example of a MythTV box with 2 x USB (DVB-T) and 2 x PCI (DVB-S) cards. The Udev rule specifically identifies the devices and allocates the same /dev symlink each boot time. This stops adapter nos switching on reboot and hotplugging.

For those using pre-compiled packages it is common for the DVB receivers to be in /dev/dvb (MythTV Compile option) to save building your own custom version the example below drops the adapters in the common dvb directory, but calls them adapter101, adapter102 etc and so on. In otherwords clearly separate from the standard adapter references. MythTV Setup can then be easily configured.

# /etc/udev/rules.d/10-local.rules
# 
# To Ientify serial nos etc for a Device call
# udevadm info -a -p $(udevadm info -q path -n /dev/dvb/adapter0/frontend0)
# 

# Create a symlink /dev/dvb/adapter101 pointing to Nova T with serial 4030521975
SUBSYSTEM=="dvb", ATTRS{manufacturer}=="Hauppauge", ATTRS{product}=="Nova-T Stick", ATTRS{serial}=="4030521975", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter101/%%s $${K#*.}'", SYMLINK+="%c"

# Create a symlink /dev/dvb/adapter102 pointing to Nova T with serial 4030980023
SUBSYSTEM=="dvb", ATTRS{manufacturer}=="Hauppauge", ATTRS{product}=="Nova-T Stick", ATTRS{serial}=="4030980023", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter102/%%s $${K#*.}'", SYMLINK+="%c"

# Create a symlink /dev/dvb/adapter103 pointing to HVR3000 with bus ID 0000:04:07.2
SUBSYSTEM=="dvb", ATTRS{vendor}=="0x14f1", KERNELS=="0000:04:07.2", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter103/%%s $${K#*.}'", SYMLINK+="%c"

# Create a symlink /dev/dvb/adapter104 pointing to HVR3000 with bus ID 0000:04:09.2
SUBSYSTEM=="dvb", ATTRS{vendor}=="0x14f1", KERNELS=="0000:04:09.2", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter104/%%s $${K#*.}'", SYMLINK+="%c"
  

Example for twin tuner cards with no difference in udevadm info output

For some twin tuner devices you won't be able to differentiate between tuners on the udevadm info output. You can check this by doing a udevadm info for each tuner on the same card/adapter/USB unit, and feeding the result to 2 files. Then use the diff command on the two files.

You can use the fact that they will enumerate them in sequence & the ENV{} command to fix this.The way this works is that in the udev rules below, ENV{kworld}!="two" tests to see if kworld is set to two, if not then it must be the first tuner on the adapter because it is the first time this rule has been matched, so it then sets it using ENV{kworld}="two". This means that for the next tuner, the next run through this rule will have kworld set to two, the first rule fails, and the 2nd rule gets invoked and works. Note also that ALL of the rules get executed even if one matches, so you need to be careful that the 2nd rule can't match as well as the first!

Notice that a test of an ENV variable is == (test if equals) or != (does not equal), and to set it you use a single = sign.

# /etc/udev/rules.d/10-dvb.rules
#
# To Ientify serial nos etc for a Device call
# udevadm info -a -p $(udevadm info -q path -n /dev/dvb/adapter0/frontend0)
#
 
# Create a symlink for single tuner Nova T device
SUBSYSTEM=="dvb", ATTRS{vendor}=="0x1131", ATTRS{device}=="0x7146", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter_nova/%%s $${K#*.}'", SYMLINK+="%c"
                                    
# Create a symlinks for both tuners of Kworld device
SUBSYSTEM=="dvb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="e399", ENV{kworld}!="two", ENV{kworld}="two", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter_kw1/%%s $${K#*.}'", SYMLINK+="%c"
SUBSYSTEM=="dvb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="e399", ENV{kworld}=="two", ENV{kworld}="one", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter_kw2/%%s $${K#*.}'", SYMLINK+="%c"

# Create a symlink for both tuners of afatech device
SUBSYSTEM=="dvb", ATTRS{idVendor}=="13d3", ATTRS{idProduct}=="3237", ENV{afatech}!="two", ENV{afatech}="two", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter_afa1/%%s $${K#*.}'", SYMLINK+="%c"
SUBSYSTEM=="dvb", ATTRS{idVendor}=="13d3", ATTRS{idProduct}=="3237", ENV{afatech}=="two", ENV{afatech}="one", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter_afa2/%%s $${K#*.}'", SYMLINK+="%c"

Note- there seems to be a bug in the example above (at least it did not work for me- Indulis Bernsteins), so you can use the example below which does work. This uses a shell script for the Pinnacle tuner to check if the 1st tuner has already been created- if it hasn't then this is the 1st tuner on the adapter/card/USB device, if the link has already been created for the 1st tuner has then this pass through the rules must be for the 2nd Pinnacle tuner. The udev rule below creates 2 new devices with known names for each adapter/USB device, symbolically linked to the each of the tuners (adapter100 and adapter101 for a DVICO dual tuner PCI adapter with easily distinguished tuners, and adapter110 and adapter111 for my Pinnacle dual tuner USB stick with no way of using ATTR for distinguishing the tuners).

# /etc/udev/rules.d/10-local.rules
#
# To Ientify serial nos etc for a Device call
#
#

# Create a symlink /dev/dvb/adapter100 pointing to dvico tuner 0
SUBSYSTEM=="dvb", ATTRS{manufacturer}=="Dvico", ATTRS{product}=="Bluebird", ATTRS{serial}=="0000d34b", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter100/%%s $${K#*.}'", SYMLINK+="%c"

# Create a symlink /dev/dvb/adapter101 pointing to dvico tuner 1
SUBSYSTEM=="dvb", ATTRS{manufacturer}=="Dvico", ATTRS{product}=="Bluebird", ATTRS{serial}=="0000534b", PROGRAM="/bin/sh -c 'K=%k; K=$${K#dvb}; printf dvb/adapter101/%%s $${K#*.}'", SYMLINK+="%c"

# Create a symlink /dev/dvb/adapter110 pointing to pinnacle tuner 0, and adapter111 for tuner 1
SUBSYSTEM=="dvb", ATTRS{manufacturer}=="PINNACLE", ATTRS{product}=="PCTV 2001e", ATTRS{serial}=="12026013", PROGRAM="/bin/sh -c ' K=%k; K=$${K#dvb}; N=$${K#*.}; if [ ! -e /dev/dvb/adapter110/$N ] ; then  printf dvb/adapter110/%%s $${K#*.}; else printf dvb/adapter111/%%s $${K#*.}; fi ; exit 0'", SYMLINK+="%c"

udevadm test is your friend! Also you can put set -xv ; straight after the ' before K=%k; to see what is happening when you test.

udevadm control --log-priority="debug-verbose"
udevadm test /class/dvb/dvb0.frontend0

More complicated setup with multi-tuner cards having no difference in udevadm info output coexisting with other cards based on the same A/V decoder

It is possible that Your setup has many different cards and some of them have multiple tuners. If different cards have the same A/V decoder - relaying on udev might be tricky as reported Vendor/Device attributes might be the same for different cards (in such case usually A/V bridge attributes are reported). Also Manufacturer attributes are not always reported. In such case only solution is to use Subsystem_Vendor/Subsystem_ID attributes. Another issue might be related to case when udev reports exactly the same output for different tuners on the same card. In my case (Piotr Oniszczuk) udev solution based on rules presented in this Wiki (p7) have issue with initialization races as each sub-device on DVB adapter (frontend, mux, dvr) are served separately so it is possible to receive adapterX with frontend from adapterY. Below is example of small tool able to deal with all above cases. To run it, launch "map-dvb-dapters.sh" Script should be called with some delay as some drivers needs some time to finish initialization (firmware load, etc). I'm using 5s delay. Installing is simple: 1. create "97-dvb-adapters-map.rules" file and add Your cards. Put this file into "/etc/udev/rules.d" dir.

# 97-dvb-adapters-map.rules file
#
# To get some details about tuners:
#   cat /var/log/kernel.log | grep "dvb\|DVB:"
#   udevadm info -a -p $(udevadm info -q path -n /dev/dvb/adapter0/frontend0)
#
# To add new card:
#   1. read subsystem_vendor & subsystem_device via udevadm info
#   2. put these values in lines
#      \
#      ATTRS{subsystem_vendor}
#      ATTRS{subsystem_device}
#      \
#   3. add desirable <name> in line:
#      \
#      <name>:%k
#      \




#----DVB-T tuners-------------
# Nova-T 0x0070:0x9002
SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0",	\
	    \
	    ATTRS{subsystem_vendor}=="0x0070",	\
	    ATTRS{subsystem_device}=="0x9002",	\
	    \
	    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
	    \
	    Hauppauge_Nova-T:%k \
	    \
	    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"


# WinTV-HVR1100 DVB-T/Hybrid 0x0070:0x9800
SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0",	\
	    \
	    ATTRS{subsystem_vendor}=="0x0070",	\
	    ATTRS{subsystem_device}=="0x9800",	\
	    \
	    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
	    \
	    Hauppauge_HVR1100:%k \
	    \
	    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"


#----DVB-S tuners-------------
# ProfTuners 7301 0xb034:0x3034
SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0",	\
	    \
	    ATTRS{subsystem_vendor}=="0xb034",	\
	    ATTRS{subsystem_device}=="0x3034",	\
	    \
	    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
	    \
	    ProfTuners_ptg7301:%k \
	    \
	    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"


# DVBSky S952 0x4254:0x0952
SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0",	\
	    \
	    ATTRS{subsystem_vendor}=="0x4254",	\
	    ATTRS{subsystem_device}=="0x0952",	\
	    \
	    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
	    \
	    DvbSky_S952:%k \
	    \
	    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"

2. Create "dvb-adapters-map.conf" file and edit to Yours needs. Put this file into "/etc/" dir.

# dvb-adapters-map.conf file
#
# This file defines mapping of given tuner (refered by name) to given symlink
# adapter numer. Tuner name must correspond with names defined in 
# 97-dvb-adapters-map.rules udev rule. Only ASCII, _, -, and spaces are allowed.
# Lines with # at begining are ingonerd.
# If adapter number is empty, script will use card_name as adapter name and
# sequential 1,2,3,etc numbers for each tuner on givenb card 

ProfTuners_ptg7301 :   22
Hauppauge_Nova-T   :   10
DvbSky_S952        :   20
Tevii_S480         :   20

3. Create "map-dvb-adapters.sh" file and put this file into "/usr/local/bin/" dir.

        
#!/bin/bash
#
# map-dvb-adapters.sh file
#
# This script allows symlinking DVB adapters to constant & user defined
# symlinks. It is usable when kernel assigns different DVB adapter number on
# every boot. Script requires:
#   1.udev rule which saves boot time adapter number assigned by kernel
#   2.conf file which defines symlinks of persistent adapter numbers
#
# Format of udev rule is following:
#SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0", \
#	    \
#	    ATTRS{subsystem_vendor}=="<vendor_id>",	\
#	    ATTRS{subsystem_device}=="<vendor_id>",	\
#	    \
#	    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
#	    \
#	    <card_name>:%k \
#	    \
#	    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"
#
# Format of conf file is following:
#    <card_name>:<symlink_number>
#
# Example:
# For 2 cards like dual DVBS S480 & quad DVBS TBS9841
# udev rule will be following:
#SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0", \
#	    \
#	    ATTRS{subsystem_vendor}=="0xa000", \
#	    ATTRS{subsystem_device}=="0x4000", \
#	    \
#	    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
#	    \
#	    Tevii_S480:%k \
#	    \
#	    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"
#
#SUBSYSTEM=="dvb", KERNEL=="dvb[0-9].frontend0", \
#	    \
#	    ATTRS{subsystem_vendor}=="t.b.i", \
#	    ATTRS{subsystem_device}=="t.b.i", \
#	    \
#	    , PROGRAM="/bin/sh -c 'rc=`grep -c -s %k /tmp/dvb-adapter-%k.map`; if [ $rc != 0 ] ; then exit 0 ; else echo \
#	    \
#	    tbs9841:%k \
#	    \
#	    >> /tmp/dvb-adapter-%k.map; fi ; exit 0'"
#
#
# .conf file can be following:
# Tevii_S480 : 20
# tbs9841    : 22
# 
# Launching script will result with following symlinks
# /dev/dvb/adapterA -> /dev/dvb/adapter20
# /dev/dvb/adapterB -> /dev/dvb/adapter21
# /dev/dvb/adapterC -> /dev/dvb/adapter22
# /dev/dvb/adapterD -> /dev/dvb/adapter23
# /dev/dvb/adapterE -> /dev/dvb/adapter24
# /dev/dvb/adapterF -> /dev/dvb/adapter25
# where A&B are boot time adapters created by kernel for Tevii_S480
# while C,D,E,F are boot time adapters created by kernel for tbs9841





map_file="/tmp/dvb-adapters.map"
conf_file="/etc/dvb-adapters-map.conf"
udev_rule="/etc/udev/rules.d/97-dvb-adapters-map.rules"


echo "DVB adapters mapping utility v1.1"
echo "Copyright: Piotr Oniszczuk, warpme-at-o2.pl"


if [ ! -e ${udev_rule} ] ; then
  echo "ERROR: \"${udev_rule}\" not installed !"
  echo "       Please install this file into /etc/udev/rules.d/"
  echo "       Now exiting..."
  exit 1
fi

if [ -z $1 ] ; then
  echo "Using boot time generated .map file"
else
  if [ $1 = "requery_udev" ] ; then
    echo "Asking udev for regeneration .map file..."
    rm -rf ${map_file}
    rm -rf /tmp/dvb-adapter-dvb*.map
    KERNEL_LIST=`ls -1 /sys/class/dvb/dvb* | grep "frontend0" | sed "s/\://" 2>/dev/null`
    for adapter in ${KERNEL_LIST} ; do
      echo "    Querying ${adapter}"
      udevadm test ${adapter} > /dev/null 2> /dev/null
    done
  else
    echo "ERROR: Unknown commandline parameter. Exiting..."  	
  fi
fi

MAPS_LIST=`ls -1 /tmp/dvb-adapter-dvb*.map 2>/dev/null`
for file in ${MAPS_LIST} ; do
  cat ${file} >> ${map_file}
done
rm -rf /tmp/dvb-adapter-dvb*.map

if [ ! -e ${map_file} ] ; then
  echo "ERROR: \"${map_file}\" not found !"
  echo "       You can regenerate this file by calling this sctipt"
  echo "       with \"requery_udev\" command-line parameter"
  echo "       Now exiting..."
  exit 1
fi

if [ ! -e ${conf_file} ] ; then
  echo "ERROR: Missing \"${conf_file}\" file !"
  echo "       You should put this file in /etc dir"
  echo "       Now exiting..."
  exit 1
fi

ADAPTERS_LIST=`cat ${map_file} 2>/dev/null`

mv ${map_file} ${map_file}.old

function DoSymlink() {
  if [ -z ${prefix} ] ; then
    path="/dev/dvb/${name}."
    prefix=1
  else
    path="/dev/dvb/adapter"
  fi
  for adapter in ${ADAPTERS_LIST} ; do
    rc=`echo ${adapter} | grep -s "${name}"`
    if /usr/bin/test ! -z "${rc}" ; then
      rc=`echo ${adapter} | sed 's/.*dvb\([0-9]\)\.frontend.*/\1/'`
      echo "card_name:\"${name}\",kernel:adapter$rc->${path}${prefix}"
      rm -rf ${path}${prefix}
      ln -sf /dev/dvb/adapter$rc ${path}${prefix}
      prefix=$((${prefix} + 1))
    fi
  done
}

card_list=`cat ${conf_file} | sed -e '/^#/ d' -e '/^$/ d' -e 's/ //g'`

for card in ${card_list} ; do
  name=`echo ${card} | sed 's/\(.*\)\:.*/\1/'`
  prefix=`echo ${card} | sed 's/.*:\([0-9]*\)/\1/'`
  DoSymlink
done

echo "All adapters mapped sucessfuly. Exiting..."
exit 0

Example V4L2 device rule file (for an analog Hauppauge WinTV PVR USB2 device)

Use udevadm to find the WinTV PVR USB2 serial number as documented above. This script creates a symlink of /dev/video300 (and /dev/radio300) to the base /dev/video{n} (and /dev/radio{n}) devices. Alter the serial number and symlink name to your requirements.

# /etc/udev/rules.d/10-local-pvrusb2.rules
# 

# Create a persistent name /dev/video300 symlink to the device name assigned by the kernel
SUBSYSTEM=="video4linux", KERNEL=="video[0-9]*", ATTRS{manufacturer}=="Hauppauge", ATTRS{product}=="WinTV", ATTRS{serial}=="2401-00-0084xxxx", SYMLINK+="video300"
# Create a persistent name /dev/radio300 symlink to the device name assigned by the kernel
SUBSYSTEM=="video4linux", KERNEL=="radio[0-9]*", ATTRS{manufacturer}=="Hauppauge", ATTRS{product}=="WinTV", ATTRS{serial}=="2401-00-0084xxxx", SYMLINK+="radio300""

Example DVB device rule file (for the digital side of the Hauppauge HVR-1950 device)

Use udevadm to find the HVR-1950 serial number as documented above. This script creates a symlink of /dev/dvb/adapter200/<x> to the base /dev/dvb/adapter{n}/<x> devices using udev environmental variables (no shell programming required as above). Alter the serial number and symlink name to your requirements.

# /etc/udev/rules.d/10-local-hvr1950.rules
#

SUBSYSTEM=="dvb", ATTRS{manufacturer}=="Hauppauge", ATTRS{product}=="WinTV", ATT
RS{serial}=="7300-00-F0xxxxxx", SYMLINK+="dvb/adapter200/$env{DVB_DEVICE_TYPE}$e
nv{DVB_DEVICE_NUM}"

Alternatives to udev for naming for DVB cards (The adapter_nr module option)

In some instances where one may not be able to find enough ATTRS to distinguish the cards installed. (This can occur when using multiple identical cards that udev doesn't provide a serial number, or for two cards with two tuners on it) An alternate means of ensuring the adapter number remains constant is to use the the adapter_nr module option. For example:

# /etc/modules.d/dvb

# Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)
options dvb_usb_vp7045 adapter_nr=4

# LifeView TV Walker Twin DVB-T USB2.0
options dvb_usb_m920x adapter_nr=5,6

is used to specify that the Twinhan card is always adapter 4, and the LifeView Card (this card has two receivers) is always adapter 5 & 6. (In my case, I intentionally didn't use 0,1,2 so that any new DVB cards installed into the computer don't conflict with my setup in any way.)

Another example (added November 2009, using MythTV 0.22 with a 2.6.31 kernel): a backend with two Hauppauge Nova-S-Plus DVB-S cards and a Hauppauge Nova-T 500 Dual DVB-T card. Adding these module options to modprobe configuration:

# /etc/modprobe.d/dvb.conf

# Hauppauge Nova-S-Plus DVB-S
options cx88-dvb adapter_nr=0,1

# Hauppauge Nova-T 500 Dual DVB-T, which also requires its low noise amplifier to be switched on
options dvb-usb-dib0700 adapter_nr=2,3 force_lna_activation=1

makes sure that the DVB-S cards are always adapters 0 and 1, and the DVB-T card's dual tuners show up as adapters 2 and 3. This is confirmed in the system log, where the adapters are numbered correctly despite being detected in a different order:

$ dmesg | grep "registering adapter"
[    7.163022] DVB: registering adapter 2 frontend 0 (DiBcom 3000MC/P)...
[    9.840541] DVB: registering adapter 0 frontend 0 (Conexant CX24123/CX24109)...
[    9.841996] DVB: registering adapter 1 frontend 0 (Conexant CX24123/CX24109)...
[   10.522401] DVB: registering adapter 3 frontend 0 (DiBcom 3000MC/P)...

Testing your udev rules

To test your udev rules, you can either reboot the computer or use the following commands as root:

  • udevtrigger
  • udevcontrol
  • udevadm trigger


Availability of the commands will likely depend on your distribution and kernel version.

Caveats

Mucking with your device drivers may require you to shut down the MythTV backend process. You should experiment with this procedure only when you have no recordings scheduled.

The identifying information you locate using this procedure could change if you upgrade your drivers. Likewise, if you add new hardware, you might need to tweak your rules -- perhaps a rule that serves to uniquely distinguish two devices won't uniquely distinguish a third device. The more specific you can make your rules, the less likely you'll have to tweak them when you add hardware. If your udevadm info output includes a serial number, that can be a great way to uniquely identify your hardware, particularly if you've got multiple identical encoders connected to different inputs. On the other hand, if you're too specific, you might have problems if you replace the hardware with a very similar device. For instance, if you use a serial number but the device breaks and you replace it with an identical unit, you'll need to reconfigure udev.

Device drivers occasionally take a few seconds to create device files for a device. I ran into this problem with a Hauppauge WinTV-PVR-USB2; device files didn't appear the moment I typed modprobe pvrusb2. I initially believed my rules weren't working, when in fact I was just being impatient.

Additional information

Additional information on udev can be found at: