Device Filenames and udev

From MythTV Official Wiki
Revision as of 02:19, 17 April 2010 by Indulis (talk | contribs) (Example for twin tuner cards with no difference in udevinfo output)

Jump to: navigation, search
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 consistent. 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 consistent, read on.


Important.png Note: This wiki entry describes configuring udev to create consistent 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 udevinfo or udevadm to obtain information on the device:

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

or

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 udevinfo command has been renamed to udevadm on some recent distributions, so try both commands. 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 udevinfo/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 udevinfo/udevadm to a file (by adding > ~/filename.txt to the command). If you redirect each output to a different file, you can 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 udevinfo output for two video devices, a PcHDTV HD-3000 and a Hauppauge WinTV-PVR-USB2. The udevinfo/udevadm 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 udevinfo, 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 udevinfo 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 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
# udevinfo -a -p $(udevinfo -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 udevinfo output

For some twin tuner devices you won't be able to differentiate between tuners on the udevinfo/udevadm output. You can check this by doing a udevinfo/udevadm 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
# udevinfo -a -p $(udevinfo -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 that 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 2nd example which uses a shell script to do the same job. That is, create 2 new devices at a known location, symbolically linked to the correct USB tuner.

# /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 ' before K=%k; to see what is happening.

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

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)...

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 udevinfo 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: