DVB with the pcHDTV HD3000

If you're new to digital television, you might like to have a look at the first chapter, to get a feel for what things were like in the "Dark Ages" before DVB support for the pcHDTV card. This is the second chapter of the pcHDTV driver story. For a similar guide showing how to configure the Air2PC card, see here instead.

The DVB driver for the pcHDTV HD2000 and HD3000 card is now in kernels 2.6.12 and up. This guide tries to explain the steps to using this new DVB driver. The initial thread about DVB driver support in kernel 2.6.12 in the pcHDTV forums is here, and the linuxtv folks also have this page about it. But let's go slow, and I'll try to explain all the steps in detail as best I can. By the way, we're not talking here about DVB (the European broadcast standard) but about DVB (the support for digital video broadcast within the Linux kernel), it's a common confusion as explained here, especially now that support for ATSC/8VSB has been added to the Linux DVB-API.

Install kernel 2.6.15

Either install Ubuntu 6.06 (Dapper Drake), or if you are using Debian then install the kernel 2.6.15 (or later). Debian always has builds of recent 2.6 kernels. For example, on Feb 26 2006, installing the package linux-image-686-smp now gives you 2.6.15, which has the DVB drivers all set to go.
  apt-get install linux-image-686-smp
So by using Debian's pre-built kernel, you can save yourself quite a bit of build time, at the expense of some reliability, as described in the following section.

Roll your own

If you would like to add support for the new FE_SET_FRONTEND_TUNE_MODE ioctl with this patch from Andrew de Quincey, then building your own kernel is (for now) still the only option. This patch allows you to set the tuning mode to FE_TUNE_MODE_ONESHOT, which helps a lot to reduce events from the frontend.

Another aspect to consider is the I2C interrupts. Improperly handling these can cause lockups. Inkling describes the beginnings of a search for a new home for the I2C interrupt handler here, to help get the housing requirements of this vital little creature a little bit less misunderstood. Inkling also discovered the reason for the "stuck" HD-3000 signal scan (where pchdtvr shows all channels at the same 100% level. As he explains in pchdtvr.c (see the section "KNOWN BUGS IN DRIVERS"), it's due to a bug with i2c-algo-bit in Linux kernel. Inkling developed a patch against v4l-dvb 2006-Feb-20 mercurial (hg) CVS to enable i2c hardware in cx88-i2c for the HD3000. GrepTar describes merging Inkling's patch to vanilla kernel and kindly provided a link to download the new patch.

The module to load for terrestrial digital HDTV (8VSB ATSC) is cx88-dvb, and the module to load for analog NTSC is cx8800. More on how to load the modules and what to expect later, first let's look at what needs to be configured in the kernel .config file to build them.

When compiling your kernel, DVB_OR51132 needs to be set to "m". If that gives you the following problem when you boot:
    cx88_dvb: Unknown symbol cx22702_attach
then it means you're missing the DVB_CX22702 from your .config file. Also, CONFIG_VIDEO_CX88 and CONFIG_VIDEO_CX88_DVB both need to be set to "m" for the analog (NTSC) driver cx8800 to be built.

The config make gconfig graph goes like this (use Jason Wies's Kernel Configuration Archive to see the full help text for each):

Device-drivers ->

  Multimedia devices ->

    [-] Video for Linux ->
      Video for Linux ->
        Video Adapters
        [-] Conexant 2388x (bt878 successor) support   (CONFIG_VIDEO_CX88=m)
          [-] DVB support for cx2388x based TV Cards   (CONFIG_VIDEO_CX88_DVB=m)

    Digital Video Broadcasting Devices ->
      [-] DVB for Linux                                (CONFIG_DVB=m)
        [-] DVB Core Support                           (CONFIG_DVB_CORE=m)
          Customize DVB Frontends ->
            [-] Conexant cx22702 demodulator (OFDM)    (CONFIG_DVB_CX22702=m)
            [-] OR51132 based (pcHDTV HD3000 card)     (CONFIG_DVB_OR51132=m)

Build the kernel however you usually build your kernel. On Debian, I used Manoj Srivastava's amazing make-kpkg tool, as follows:
  tar jxvf linux-
  cd linux-
  apt-get install libglade2-dev
  make gconfig
  fakeroot make-kpkg --initrd kernel_image modules_image
This produces a file called kernel-image- in the directory containing linux- (i.e. the parent directory). I installed it (after checking its contents) as follows:
  dpkg-deb -c kernel-image-
  dpkg -i kernel-image-
During installation, the initial ramdisk is created. The contents of the initrd.img- can be viewed by loopback mounting it, to check it has all the modules you expect or to edit the /mnt/test/loadmodules script to change the sequence the modules will be loaded in, as follows:
  mount -t cramfs -o loop initrd.img- /mnt/test
For more details on how to decide which modules will be included and the order they'll be loaded, see here. If you need to remove the kernel package because you have rebuilt it and want to try with a new one, use:
   dpkg -r kernel-image-
   dpkg --purge kernel-image-
Probably all these details will seem excessive if you're already familiar with Debian, but this is one the first kernels I've built since I've been using Debian, so it's still fairly new to me.

Download the Firmware

If you're behind an http application proxy firewall, set up your $HOME/.wgetrc with your proxy as follows:
Download the firmware using the scripts contained in the Linux kernel sources Documentation/dvb directory, e.g.:
  cd ~/linux-
  perl ./get_dvb_firmware or51132_qam
  perl ./get_dvb_firmware or51132_vsb
You can also download the firmware files from here on the pcHDTV downloads page. Now copy the files dvb-fe-or51132-vsb.fw and dvb-fe-or51132-qam.fw to /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version). For Debian, I copied them as follows:
  cp dvb-fe-or51132-vsb.fw /usr/lib/hotplug/firmware/
  cp dvb-fe-or51132-qam.fw /usr/lib/hotplug/firmware/
For Ubuntu 6.06 Dapper Drake the firmware files belong in /lib/firmware so I copied them as follows:
  sudo cp dvb-fe-or51132-vsb.fw /lib/firmware/
  sudo cp dvb-fe-or51132-qam.fw /lib/firmware/
Sometimes, even though the firmware is present in the correct location, it still doesn't get uploaded by the hotplug system. If this is the case for you, it may be because of the same problem as described here and here.

The fix I used on Debian was to add the following line to my /etc/udev/udev.rules file:
ENV{UDEVD_EVENT}=="1",   RUN+="/sbin/udev_run_hotplugd"

I then restarted udev using:
  invoke-rc.d udev restart

Load the DVB Kernel module

To load the module for digital over-the-air 8VSB ATSC, use the following sequence of commands. The reason for all the "remove" commands is that after a reboot you may find that some of the modules you don't want have been loaded. It's safest to really clean things up, before loading the cx88-dvb module, as follows:

  modprobe -rv cx88_blackbird
  modprobe -rv cx88-dvb
  modprobe -rv cx8800
  modprobe -v cx88-dvb

This should cause the device directory /dev/dvb/adapter0 to appear. It should contain the following devices: demux0, dvr0, frontend0 and net0. The list would be as follows (this is for two pcHDTV HD3000 cards), showing the major/minor numbers and permissions like this:

crw-rw----  1 root video 212, 4 2005-07-31 22:42 /dev/dvb/adapter0/demux0
crw-rw----  1 root video 212, 5 2005-07-31 22:42 /dev/dvb/adapter0/dvr0
crw-rw----  1 root video 212, 3 2005-07-31 22:42 /dev/dvb/adapter0/frontend0
crw-rw----  1 root video 212, 7 2005-07-31 22:42 /dev/dvb/adapter0/net0

crw-rw----  1 root video 212, 68 2005-07-31 22:42 /dev/dvb/adapter1/demux0
crw-rw----  1 root video 212, 69 2005-07-31 22:42 /dev/dvb/adapter1/dvr0
crw-rw----  1 root video 212, 67 2005-07-31 22:42 /dev/dvb/adapter1/frontend0
crw-rw----  1 root video 212, 71 2005-07-31 22:42 /dev/dvb/adapter1/net0

In this pcHDTV forum message, leeolds describes that sometimes the HD3000 card isn't detected, and a workaround is to load the modules in two steps, with the extra parameter card set to 22 for the cx88xx module, as follows:
  modprobe -v cx88xx card=22 
  modprobe -v cx88-dvb 

To unload the cx88-dvb driver (this also conveniently unloads all of the modules it depends on), use:
  modprobe -rv cx88-dvb

Output of the load command modprobe -v cx88-dvb should be as follows:
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/

Output of the unload command modprobe -rv cx88-dvb should be as follows:
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/

When you run the command dmesg the output should contain something similar (this is for two HD3000 cards) to the following:
Linux video capture interface: v1.00
cx2388x dvb driver version 0.0.4 loaded
cx88[0]: subsystem: 7063:3000, board: pcHDTV HD3000 HDTV [card=22,autodetected]
tuner 1-0061: chip found @ 0xc2 (cx88[0])
tuner 1-0061: type set to 52 (Thomson DDT 7610 (ATSC/NTSC))
ACPI: PCI Interrupt 0000:04:02.2[A] -> GSI 18 (level, low) -> IRQ 50
cx88[0]/2: found at 0000:04:02.2, rev: 5, irq: 50, latency: 64, mmio: 0xdc000000
cx88[0]/2: cx2388x based dvb card
DVB: registering new adapter (cx88[0]).
DVB: registering frontend 0 (pcHDTV HD3000 HDTV)...
cx88[1]: subsystem: 7063:3000, board: pcHDTV HD3000 HDTV [card=22,autodetected]
tuner 2-0061: chip found @ 0xc2 (cx88[1])
tuner 2-0061: type set to 52 (Thomson DDT 7610 (ATSC/NTSC))
ACPI: PCI Interrupt 0000:04:03.2[A] -> GSI 16 (level, low) -> IRQ 169
cx88[1]/2: found at 0000:04:03.2, rev: 5, irq: 169, latency: 64, mmio: 0xde000000
cx88[1]/2: cx2388x based dvb card
DVB: registering new adapter (cx88[1]).
DVB: registering frontend 1 (pcHDTV HD3000 HDTV)...

Using the DVB kernel modules

Get the latest dvb-apps from the linuxtv CVS, using:
  cvs -z3 -d ':pserver:anonymous@cvs.linuxtv.org:/cvs/linuxtv' co -P dvb-apps
If you're behind an http application proxy firewall, you'll need to add the proxy to the command like this:
  cvs -z3 -d ':pserver;proxy=your-proxy.your-domain;proxyport=80:anonymous@cvs.linuxtv.org:/cvs/linuxtv' co -P dvb-apps

Some distributions include a dvb-utils package that has tzap. Don't use tzap, it is not a replacement for azap. If you can't find azap, it probably means you have an old version of the dvb-apps, so just build the dvb-apps from CVS and use them locally as shown in the examples here.

Build the dvb-apps by running make in the top directory.

Go into the util/scan directory, and run the following example:
  cd dvb-apps/util/scan && ./atscscan atsc/us-NTSC-center-frequencies-8VSB

At this point, the kernel module will try to load the firmware for the HD3000 card. Check your "dmesg" output. If you see this in "dmesg", then the firmware isn't being uploaded by the hotplug subsystem:
  or51132: Waiting for firmware upload(dvb-fe-or51132-vsb.fw)...
  or51132: No firmware uploaded(timeout or file not found?)

As described in the section above, even though the firmware is present in the correct location, it may still not get uploaded by the hotplug system. Please try the fix described in that section.

Once the firmware loads successfully, dmesg will show the following message:
  or51132: Waiting for firmware upload(dvb-fe-or51132-vsb.fw)...
  or51132: Version: 10001134-19430000 (113-4-194-3)
  or51132: Firmware upload complete.

Once the firmware is loaded, the atscscan runs as follows.
  cd dvb-apps/util/scan && ./atscscan atsc/us-NTSC-center-frequencies-8VSB
Only the summary section dumping lists at the end is what we're interested in:
dumping lists (26 services)
KNTV-HD :207000000:8VSB:65:68:4
NBC Wea :207000000:8VSB:81:84:5
KBWB-HD :503000000:8VSB:49:52:3
KBWB-SD :503000000:8VSB:65:68:4
KGO-DT :533000000:8VSB:49:52:3
KGO-DT :533000000:8VSB:65:68:4
KPIX DT:563000000:8VSB:49:52:1
KMTP Digital Television:587000000:8VSB:49:52:3
KKPX Faith:635000000:8VSB:97:100:6
KKPX Worship:635000000:8VSB:81:84:5
KKPX Pax East:635000000:8VSB:65:68:4
KKPX Digital Television:635000000:8VSB:49:52:3

Creating the $HOME/.azap/channels.conf

Put the last section from the above output from atscscan into $HOME/.azap/channels.conf. (You may need to edit the first column to remove spaces. Doing that makes it more convenient to pass the contents of this first column as the command-line parameter to the various DVB tools.) Use the "-r" option to ./dvb-apps/util/szap/azap to tune to a terrestrial 8VSB ATSC channel:
  ./dvb-apps/util/szap/azap -r KNTV-HD

This will show output something like the following. The thing to look for is the FE_HAS_LOCK, which means that the frontend kernel module has tuned to the channel.
using '/dev/dvb/adapter0/frontend0' and '/dev/dvb/adapter0/demux0'
tuning to 207000000 Hz
video pid 0x0041, audio pid 0x0044
status 00 | signal 3999 | snr cd37 | ber 00000000 | unc 00000000 |
status 1f | signal cb84 | snr f8cf | ber 00000000 | unc 00000000 | FE_HAS_LOCK
status 1f | signal cb84 | snr f8b3 | ber 00000000 | unc 00000000 | FE_HAS_LOCK

Note that neither the pcHDTV HD-2000 nor the HD-3000 card support the FE_READ_BER ioctl, so the ber reported by azap is undefined. It's usually 00000000 for the HD-3000 card, and something like FFFFFFF3 for the HD-2000 card.

While azap is running in one terminal, you can launch mplayer on /dev/dvb/adapter0/dvr0 to watch the stream. This will display the video without deinterlacing (not pretty) and output the audio using AC3 passthrough. Remove the -ac hwac3 flag if you're not using an external dolby decoder.
  mplayer -ac hwac3 /dev/dvb/adapter0/dvr0

To turn on software deinterlacing (which will use considerable CPU) and 16:9 aspect ratio correction (to help make things look less "stretched"), use:
  mplayer -ac hwac3 -vf pp=lb -monitoraspect 16:9 /dev/dvb/adapter0/dvr0

To save the individual stream to the hard drive, one way is to use:
  cat /dev/dvb/adapter0/dvr0 > $HOME/test.mpg

To save the full ATSC stream, see below.

You can playback $HOME/test.mpg with mplayer, or use xine.

Viewing the PIDs

When a channel is tuned using azap, you can view the PIDs multiplexed within that channel using dvbscan as follows:
  ./dvb-apps/util/scan/dvbscan -c

For example, while running azap -r KNTV-HD, the output from dvbscan -c is as follows:

using '/dev/dvb/adapter0/frontend0' and '/dev/dvb/adapter0/demux0'
service is running. Channel number: 11:1. Name: 'KNTV-HD'
service is running. Channel number: 11:2. Name: 'NBC Wea'
dumping lists (2 services)
KNTV-HD                  (0x0004) 00: PCR == V   V 0x0041 A 0x0044 (eng) 0x0044 (eng)
NBC Wea                  (0x0005) 00: PCR == V   V 0x0051 A 0x0054 (eng) 0x0054 (eng)

Another way to view the PIDs is to use ./dvb-apps/util/dvbtraffic/dvbtraffic by just running it and watching which PIDs show up as having a lot of bandwidth associated with them:

0000     9 p/s     1 kb/s    14 kbit
0040    10 p/s     1 kb/s    16 kbit
0041  9659 p/s  1773 kb/s 14527 kbit
0044   280 p/s    51 kb/s   422 kbit
0050    10 p/s     1 kb/s    16 kbit
0051  2146 p/s   393 kb/s  3227 kbit
0054   280 p/s    51 kb/s   422 kbit
1d00     5 p/s     0 kb/s     8 kbit
1d02     2 p/s     0 kb/s     4 kbit
1e00     7 p/s     1 kb/s    11 kbit
1e02     1 p/s     0 kb/s     2 kbit
1e80     0 p/s     0 kb/s     1 kbit
1ffb    40 p/s     7 kb/s    60 kbit
1fff   442 p/s    81 kb/s   665 kbit
2000 12901 p/s  2368 kb/s 19403 kbit

For example, with KNTV-HD tuned using azap, the PIDs 0x0041 and 0x0044 (65 and 68 decimal) as well as the PIDs 0x0051 and 0x0054 (81 and 84 decimal) show a lot of bandwidth.

You can also find the PIDs by running ./dvb-apps/util/scan -c while the channel is tuned, which may be easier than viewing the dvbtraffic output especially if your signal is somewhat noisy.

These PIDs can be seen in your $HOME/.azap/channels.conf in columns four and five. They correspond to the audio and video PIDs for the two "stations" (actually referred to as virtual channels, or VCs in the ATSC spec) being transmitted with the 207000000 frequency, as follows:
  NBC Wea:207000000:8VSB:81:84:5
The 4 and 5 in the last column at the end are the subchannel numbers, which can be selected using the mplayer option -tsprog, e.g. to play subchannel 4, use:
  mplayer -tsprog 4 -ac hwac3 /dev/dvb/adapter0/dvr0

In the avsforum, the post by JarginAU is well worth checking out, as it provides additional insight to using the DVB tools.

Recording a full ATSC stream

Although it's possible to dump the output from /dev/dvb/adapter0/dvr0 to the hard drive, sometimes you want to save the entire raw ATSC stream. To do this, use ./dvb-apps/test/test_dvr as follows:

  ./dvb-apps/util/szap/azap -r KTVUHD
  BUF_SIZE=1925120 ./dvb-apps/test/test_dvr $HOME/test.mpg 0x2000

Or to record from a second HD3000 card (if you're using two in the same machine), use:
  ./dvb-apps/util/szap/azap -a 1 -f 0 -r KQED-HD
  DEMUX=/dev/dvb/adapter1/demux0 DVR=/dev/dvb/adapter1/dvr0 BUF_SIZE=1925120 ./dvb-apps/test/test_dvr $HOME/test2.mpg 0x2000

Playback using xine

The regular xine-ui package with Debian is able to play back full ATSC recorded streams. e.g. to playback the stream recorded above, you'd use:

  xine $HOME/test.mpg

Don't forget about xine's convenient "zoom" key z to zoom in (Z to zoom out), which is useful for when stations transmit 4:3 aspect ratio content (usually the local news) at 16:9 aspect ratio, leaving a black area around the picture.

There's also a tempting-looking "DVB" button in the xine GUI. Jack Kelliher recently posted this patch to the xine-devel mailing list. It has a small typo in the following line, where the second (") should be replaced with a single quote ('), but otherwise it applies fairly cleanly:
 +       _("input_dvb: dvbc mrl specified but the tuner doesn"t appear to be QAM (DVB-C)\n"));
To apply Jack's patch to xine-lib, proceed something like this:
   wget http://easynews.dl.sourceforge.net/sourceforge/xine/xine-lib-1.1.0.tar.gz
   wget http://easynews.dl.sourceforge.net/sourceforge/xine/xine-ui-0.99.4.tar.gz

   tar zxvf xine-lib-1.1.0.tar.gz
   ln -s xine-lib-1.1.0 xine-lib
   cat jack_kelliher_xine_lib_input_dvb_patch | patch -p0 >patch.out 2>patch.err
The magical result of Jack's patch is that once you copy your channels.conf file into your $HOME/.xine directory, and launch xine, now when you press the "DVB" button in the GUI, it actually plays the first channel it finds. It works great on standard definition DTV channels, and on 1280x720 channels.

With the default xine settings, the HDTV 1920x1088 channels had a lot of breakup and glitches, which can be fixed by increasing the setting for Number of video buffers under the engine tab in the xine configuration dialog box (first make sure you have selected the Master of the known universe setting on the gui tab, then click the right-arrow at the top of the dialog box to reveal the engine tab).

Pressing the KP9 (keypad "9"/"PgUp") and KP3 (keypad "3"/"PgDn") keys in xine, or using the scroll wheel on your mouse, will switch channels to whatever you have in your $HOME/.xine/channels.conf Using the scroll wheel brings up a convenient on-screen overlay menu listing your channels, and clicking with the left mouse button activates your selection. You can also tune directly to a channel by giving the channel name (from the first column of your $HOME/.xine/channels.conf, like this:
   xine dvb://KQED-HD
It's a little bit slow to switch channels, but it's far more reliable than with the non-DVB drivers, which tended to loose audio or get into a sort of slow-video mode when changing channels, so this is a very useful patch for xine and well worth trying out. It's fairly short, so it's well worth reading, with a view to patching other applications for the American/Canadian ATSC market.

Compiling xine-hd

The only "gotcha" with plain xine is that you can't select the subchannel in the way mplayer can (using its -tsprog flag). The pcHDTV folks provide a patched version of xine called "xine-hd" which can select the subchannel using the "-C" option, e.g.:

  xine -C 52.4 $HOME/test.mpg

The xine-hd download provided by pcHDTV hasn't yet been patched to compile with gcc4, nor for ATSC DVB support (yet), so if your system is using gcc4 by default, it is easiest to just compile xine-hd using gcc3 instead. Set your PATH to pick up gcc3 first.

You may run into the following compile problem with building the xine-hd library:

input_dtv.c: In function `dtv_plugin_set_channel':
input_dtv.c:266: error: `VIDEO_MODE_ATSC' undeclared (first use in this function)

The above is what happens if you try to compile xine-hd and haven't yet patched your videodev.h file as it says in the pcHDTV readme file within the pcHDTV 2.6.12 extras (04/09/05). Look in the pcHDTV-extras/v4l2-driver directory, and notice that the make install target of the Makefile in that directory does the following:

mkdir -p /usr/include/linux; cp -v videodev2.h videodev.h /usr/include/linux
patch -Np0 /usr/include/linux/videodev2.h <videodev2-patch

Don't install the /lib/modules/ driver, though, because if it gets loaded it will crash the kernel!

The pcHDTV version of xine has the -C option for selecting which subchannel to playback from full ATSC stream captures, for example:
  ./dvb-apps/util/szap/azap -r KQED-HD
  BUF_SIZE=1925120 ./dvb-apps/test/test_dvr $HOME/test.mpg 0x2000
  xine -C 52.4 $HOME/test.mpg

How about good old Analog (NTSC)?

The "cx8800" module implements the V4L2 driver, used for analog NTSC reception with the pcHDTV HD3000 card. It seems to be safest to first clean things up before loading it, so I use the following sequence:
  modprobe -rv cx88_blackbird
  modprobe -rv cx88-dvb
  modprobe -rv cx8800
  modprobe -v cx8800
It works fine with the tvtime application, to view local analog NTSC broadcasts. To get sound in tvtime, apparently one is supposed to use the special proprietary magical cable provided by pcHDTV (just kidding, any cable will work) to connect the HD3000's line-out to the line-in on one's soundcard. I haven't gotten the driver for the line-in to work for the Audigy card in the Dell XPS, so for now I'm connecting the HD3000's line-out to a Dell AS500 "sound-bar" which hangs under the monitor and works well for listening to the local news and things like that. To run tvtime with input from a second HD3000 card, use the /dev/video1 device as follows:
  tvtime -d /dev/video1
In tvtime, use the up/down arrows to change the TV channel, to see if all of your usual broadcast NTSC channels are there.

The difference in the "dmesg" output is that loading the cx8800 module gives:
  cx2388x v4l2 driver version 0.0.4 loaded
Whereas the ATSC DVB module cx88-dvb gives:
  cx2388x dvb driver version 0.0.4 loaded

The output of the load command
  modprobe -v cx8800
for the NTSC cx8800 module is as follows:
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/
insmod /lib/modules/

When the cx8800 module is loaded, the major/minor numbers and permissions of the devices created are like this:
crw-rw----  1 root video 81, 64 2005-07-31 22:46 /dev/radio0
crw-rw----  1 root video 81, 65 2005-07-31 22:46 /dev/radio1
crw-rw----  1 root video 81, 224 2005-07-31 22:46 /dev/vbi0
crw-rw----  1 root video 81, 225 2005-07-31 22:46 /dev/vbi1
crw-rw----  1 root video 81, 0 2005-07-31 22:46 /dev/video0
crw-rw----  1 root video 81, 1 2005-07-31 22:46 /dev/video1

The output of the unload command
  modprobe -rv cx8800
for the "cx8800" module is:
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/
rmmod /lib/modules/

When you run the command dmesg the output should contain something similar (this is for two HD3000 cards) to the following:
cx2388x v4l2 driver version 0.0.4 loaded
ACPI: PCI Interrupt 0000:04:02.0[A] -> GSI 18 (level, low) -> IRQ 50
cx88[0]/0: found at 0000:04:02.0, rev: 5, irq: 50, latency: 64, mmio: 0xdb000000
cx88[0]/0: registered device video0 [v4l2]
cx88[0]/0: registered device vbi0
cx88[0]/0: registered device radio0
ACPI: PCI Interrupt 0000:04:03.0[A] -> GSI 16 (level, low) -> IRQ 169
cx88[1]/0: found at 0000:04:03.0, rev: 5, irq: 169, latency: 64, mmio: 0xdd000000
cx88[1]/0: registered device video1 [v4l2]
cx88[1]/0: registered device vbi1
cx88[1]/0: registered device radio1

Performance considerations

For the Radeon X800 card, using xorg rather than XFree gives the lowest CPU usage. Previously with XFree the machine used to run around 90% CPU, whereas now with xorg the CPU usage hovers around 40% (even for xine doing deinterlacing for 1080i streams). This still seems a lot of CPU to be using for a 3.4GHz machine, but at least when it's running at 40% the extra fan doesn't kick in, and the dreaded CONFIG_X86_MCE_P4THERMAL warning messages from ./arch/i386/kernel/cpu/mcheck/p4.c aren't seen. Using the radeon driver with xorg has definitely been an improvement. If your system has a P4 CPU and you often see messages like the following, it might be time to give xorg a try:
  kernel: CPU0: Temperature above threshold
  kernel: CPU0: Running in modulated clock mode
Update: On a second (slower) machine, I've found that using an nVidia 5200 video card (which provides support for XvMC) is a better option, and uses far less CPU.

Useful Links