Index: configure
===================================================================
--- configure.orig	2008-02-22 15:33:49.000000000 -0800
+++ configure	2008-02-22 15:34:56.000000000 -0800
@@ -158,6 +158,7 @@
   echo "  --disable-v4l            disable Video4Linux support"
   echo "  --disable-ivtv           disable ivtv support (PVR-x50) req. v4l support"
   echo "  --disable-dvb            disable DVB support"
+  echo "  --disable-r5000          disable support for R5000 USB STBs"
   echo "  --dvb-path=HDRLOC        location of directory containing"
   echo "                           'linux/dvb/frontend.h', not the"
   echo "                           directory with frontend.h [$dvb_path]"
@@ -870,6 +871,7 @@
     hdhomerun
     iptv
     ivtv
+    r5000
     joystick_menu
     lirc
     opengl_vsync
@@ -1022,6 +1024,7 @@
 dbox2_deps="backend"
 dvb_deps="backend"
 firewire_deps="backend"
+r5000_deps="backend"
 iptv_deps="backend"
 ivtv_deps="backend v4l"
 hdhomerun_deps="backend"
@@ -1153,6 +1156,7 @@
 hdhomerun="yes"
 iptv="yes"
 ivtv="yes"
+r5000="yes"
 joystick_menu="default"
 lamemp3="yes"
 lirc="yes"
@@ -2928,6 +2932,7 @@
   echo "DBox2 support             ${dbox2-no}"
   echo "HDHomeRun support         ${hdhomerun-no}"
   echo "IPTV support              ${iptv-no}"
+  echo "R5000 support             ${r5000-no}"
 fi
 
 if enabled frontend; then
Index: libs/libmythtv/cardutil.h
===================================================================
--- libs/libmythtv/cardutil.h.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/cardutil.h	2008-02-22 15:34:57.000000000 -0800
@@ -53,6 +53,7 @@
         FIREWIRE,
         HDHOMERUN,
         FREEBOX,
+        R5000,
     };
 
     static enum CARD_TYPES toCardType(const QString &name)
@@ -81,6 +82,8 @@
             return HDHOMERUN;
         if ("FREEBOX" == name)
             return FREEBOX;
+        if ("R5000" == name)
+            return R5000;
         return ERROR_UNKNOWN;
     }
 
@@ -89,13 +92,15 @@
         return
             (rawtype != "DVB")       &&
             (rawtype != "FIREWIRE")  && (rawtype != "DBOX2")   &&
-            (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX");
+            (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX") &&
+	    (rawtype != "R5000");
     }
 
     static bool         IsUnscanable(const QString &rawtype)
     {
         return
-            (rawtype == "FIREWIRE")  || (rawtype == "DBOX2");
+            (rawtype == "FIREWIRE")  || (rawtype == "DBOX2") ||
+	    (rawtype == "R5000");
     }
 
     static bool         IsEITCapable(const QString &rawtype)
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/libmythtv.pro	2008-02-22 15:34:57.000000000 -0800
@@ -489,6 +489,20 @@
         DEFINES += USING_DVB
     }
 
+    #Support for R5000 usb device
+    using_r5000 {
+        HEADERS += r5000channel.h           r5000recorder.h
+        HEADERS += r5000signalmonitor.h     r5000device.h
+	HEADERS += r5000/r5000.h            r5000/libusb_augment.h
+
+        SOURCES += r5000channel.cpp         r5000recorder.cpp
+        SOURCES += r5000signalmonitor.cpp   r5000device.cpp
+	SOURCES += r5000/r5000.c            r5000/libusb_augment.c
+
+	LIBS += -lusb
+        DEFINES += USING_R5000
+    }
+
     DEFINES += USING_BACKEND
 }
 
Index: libs/libmythtv/signalmonitor.h
===================================================================
--- libs/libmythtv/signalmonitor.h.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/signalmonitor.h	2008-02-22 15:34:57.000000000 -0800
@@ -297,7 +297,8 @@
             (cardtype.upper() == "HDTV")      ||
             (cardtype.upper() == "HDHOMERUN") ||
             (cardtype.upper() == "FIREWIRE")  ||
-            (cardtype.upper() == "FREEBOX"));
+            (cardtype.upper() == "FREEBOX")   ||
+            (cardtype.upper() == "R5000"));
 }
 
 inline bool SignalMonitor::IsSupported(const QString &cardtype)
Index: libs/libmythtv/signalmonitor.cpp
===================================================================
--- libs/libmythtv/signalmonitor.cpp.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/signalmonitor.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -41,6 +41,11 @@
 #   include "firewirechannel.h"
 #endif
 
+#ifdef USING_R5000
+#   include "r5000signalmonitor.h"
+#   include "r5000channel.h"
+#endif
+
 #undef DBG_SM
 #define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \
     "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG);
@@ -127,6 +132,14 @@
             signalMonitor = new FirewireSignalMonitor(db_cardnum, fc);
     }
 #endif
+#ifdef USING_R5000
+    if (cardtype.upper() == "R5000")
+    {
+        R5000Channel *fc = dynamic_cast<R5000Channel*>(channel);
+        if (fc)
+            signalMonitor = new R5000SignalMonitor(db_cardnum, fc);
+    }
+#endif
 
     if (!signalMonitor)
     {
Index: libs/libmythtv/cardutil.cpp
===================================================================
--- libs/libmythtv/cardutil.cpp.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/cardutil.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -1457,7 +1457,8 @@
     if (("FIREWIRE"  == cardtype) ||
         ("FREEBOX"   == cardtype) ||
         ("DBOX2"     == cardtype) ||
-        ("HDHOMERUN" == cardtype))
+        ("HDHOMERUN" == cardtype) ||
+        ("R5000"     == cardtype))
     {
         ret += "MPEG2TS";
     }
@@ -1582,7 +1583,8 @@
     if (("FIREWIRE"  == cardtype) ||
         ("FREEBOX"   == cardtype) ||
         ("DBOX2"     == cardtype) ||
-        ("HDHOMERUN" == cardtype))
+        ("HDHOMERUN" == cardtype) ||
+	("R5000"     == cardtype))
     {
         inputs += "MPEG2TS";
     }
Index: libs/libmythtv/videosource.cpp
===================================================================
--- libs/libmythtv/videosource.cpp.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/videosource.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -1297,6 +1297,23 @@
     }
 };
 
+class R5000ConfigurationGroup : public VerticalConfigurationGroup
+{
+  public:
+    R5000ConfigurationGroup(CaptureCard& a_parent):
+       VerticalConfigurationGroup(false, true, false, false),
+       parent(a_parent)
+    {
+        setUseLabel(false);
+        addChild(new SignalTimeout(parent, 2000, 1000));
+        addChild(new ChannelTimeout(parent, 9000, 1750));
+        addChild(new SingleCardInput(parent));
+    };
+
+  private:
+    CaptureCard &parent;
+};
+
 class IPTVHost : public LineEditSetting, public CaptureCardDBStorage
 {
   public:
@@ -1481,6 +1498,10 @@
 #ifdef USING_IPTV
     addTarget("FREEBOX",   new IPTVConfigurationGroup(parent));
 #endif // USING_IPTV
+
+#ifdef USING_R5000
+    addTarget("R5000", new R5000ConfigurationGroup(parent));
+#endif // USING_R5000
 }
 
 void CaptureCardGroup::triggerChanged(const QString& value) 
@@ -1668,6 +1689,10 @@
 #ifdef USING_IPTV
     setting->addSelection(QObject::tr("Network Recorder"), "FREEBOX");
 #endif // USING_IPTV
+
+#ifdef USING_R5000
+    setting->addSelection(QObject::tr("R5000 Capable STB"), "R5000");
+#endif // USING_R5000
 }
 
 class CardID : public SelectLabelSetting, public CardInputDBStorage
Index: libs/libmythtv/tv_rec.cpp
===================================================================
--- libs/libmythtv/tv_rec.cpp.orig	2008-02-22 15:34:38.000000000 -0800
+++ libs/libmythtv/tv_rec.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -50,6 +50,7 @@
 #include "hdhrchannel.h"
 #include "iptvchannel.h"
 #include "firewirechannel.h"
+#include "r5000channel.h"
 
 #include "recorderbase.h"
 #include "NuppelVideoRecorder.h"
@@ -59,6 +60,7 @@
 #include "hdhrrecorder.h"
 #include "iptvrecorder.h"
 #include "firewirerecorder.h"
+#include "r5000recorder.h"
 
 #ifdef USING_V4L
 #include "channel.h"
@@ -199,6 +201,16 @@
         init_run = true;
 #endif
     }    
+    else if (genOpt.cardtype == "R5000")
+    {
+#ifdef USING_R5000
+        channel = new R5000Channel(this, genOpt.videodev, fwOpt);
+        if (!channel->Open())
+            return false;
+        InitChannel(genOpt.defaultinput, startchannel);
+        init_run = true;
+#endif
+    }
     else // "V4L" or "MPEG", ie, analog TV
     {
 #ifdef USING_V4L
@@ -1017,6 +1029,12 @@
         recorder->SetOption("mrl", genOpt.videodev);
 #endif // USING_IPTV
     }
+    else if (genOpt.cardtype == "R5000")
+    {
+#ifdef USING_R5000
+        recorder = new R5000Recorder(this, GetR5000Channel());
+#endif // USING_R5000
+    }
     else
     {
 #ifdef USING_V4L
@@ -1230,6 +1248,15 @@
 #endif // USING_FIREWIRE
 }
 
+R5000Channel *TVRec::GetR5000Channel(void)
+{
+#ifdef USING_R5000
+    return dynamic_cast<R5000Channel*>(channel);
+#else
+    return NULL;
+#endif // USING_R5000
+}
+
 Channel *TVRec::GetV4LChannel(void)
 {
 #ifdef USING_V4L
Index: libs/libmythtv/transporteditor.cpp
===================================================================
--- libs/libmythtv/transporteditor.cpp.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/transporteditor.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -735,7 +735,8 @@
         left->addChild(new Modulation(id, nType));
     }
     else if ((CardUtil::FIREWIRE == nType) ||
-             (CardUtil::FREEBOX  == nType))
+             (CardUtil::FREEBOX  == nType) ||
+             (CardUtil::R5000    == nType))
     {
         left->addChild(new DTVStandard(id, true, true));
     }
Index: libs/libmythtv/tv_rec.h
===================================================================
--- libs/libmythtv/tv_rec.h.orig	2008-02-22 15:33:49.000000000 -0800
+++ libs/libmythtv/tv_rec.h	2008-02-22 15:34:57.000000000 -0800
@@ -39,6 +39,7 @@
 class FirewireChannel;
 class Channel;
 class HDHRChannel;
+class R5000Channel;
 
 class MPEGStreamData;
 class ProgramMapTable;
@@ -281,6 +282,7 @@
     HDHRChannel  *GetHDHRChannel(void);
     DVBChannel   *GetDVBChannel(void);
     FirewireChannel *GetFirewireChannel(void);
+    R5000Channel *GetR5000Channel(void);
     Channel      *GetV4LChannel(void);
 
     bool SetupSignalMonitor(bool enable_table_monitoring, bool notify);
Index: libs/libmythtv/r5000channel.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000channel.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,189 @@
+/**
+ *  R5000Channel
+ *  Copyright (c) 2005 by Jim Westfall, Dave Abrahams
+ *  Copyright (c) 2006 by Daniel Kristjansson
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#include "mythcontext.h"
+#include "tv_rec.h"
+#include "r5000channel.h"
+
+#define LOC QString("R5kChan(%1): ").arg(GetDevice())
+#define LOC_WARN QString("R5kChan(%1), Warning: ").arg(GetDevice())
+#define LOC_ERR QString("R5kChan(%1), Error: ").arg(GetDevice())
+
+R5000Channel::R5000Channel(TVRec *parent, const QString &_videodevice,const FireWireDBOptions &firewire_opts) :
+    DTVChannel(parent),
+    videodevice(_videodevice),
+    fw_opts(firewire_opts),
+    device(NULL),
+    current_channel(0),
+    isopen(false)
+{
+    uint subunitid = 0; // we only support first tuner on STB...
+
+    device = new R5000Device(0, subunitid, fw_opts.speed);
+
+    InitializeInputs();
+}
+
+bool R5000Channel::SetChannelByString(const QString &channum)
+{
+    QString loc = LOC + QString("SetChannelByString(%1)").arg(channum);
+    bool ok = true;
+    VERBOSE(VB_CHANNEL, loc);
+
+    InputMap::const_iterator it = inputs.find(currentInputID);
+    if (it == inputs.end())
+        return false;
+
+    QString tvformat, modulation, freqtable, freqid, dtv_si_std;
+    int finetune;
+    uint64_t frequency;
+    int mpeg_prog_num;
+    uint atsc_major, atsc_minor, mplexid, tsid, netid;
+    if (!ChannelUtil::GetChannelData(
+        (*it)->sourceid, channum,
+        tvformat, modulation, freqtable, freqid,
+        finetune, frequency,
+        dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
+        mplexid, commfree))
+    {
+        VERBOSE(VB_IMPORTANT, loc + " " + QString(
+                    "Requested channel '%1' is on input '%2' "
+                    "which is in a busy input group")
+                .arg(channum).arg(currentInputID));
+
+        return false;
+    }
+    uint mplexid_restriction;
+    if (!IsInputAvailable(currentInputID, mplexid_restriction))
+    {
+        VERBOSE(VB_IMPORTANT, loc + " " + QString(
+                    "Requested channel '%1' is on input '%2' "
+                    "which is in a busy input group")
+                .arg(channum).arg(currentInputID));
+
+        return false;
+    }
+
+    uint ichan = freqid.toUInt(&ok);
+    ok = isopen && SetChannelByNumber(ichan);
+
+    if (ok)
+    {
+        // Set the current channum to the new channel's channum
+        curchannelname = QDeepCopy<QString>(channum);
+        (*it)->startChanNum = QDeepCopy<QString>(channum);
+    }
+
+    VERBOSE(VB_CHANNEL, loc + " " + ((ok) ? "success" : "failure"));
+
+    return ok;
+}
+
+bool R5000Channel::Open(void)
+{
+    VERBOSE(VB_CHANNEL, LOC + "Open()");
+
+    if (inputs.find(currentInputID) == inputs.end())
+        return false;
+
+    if (!device)
+        return false;
+
+    if (isopen)
+        return true;
+
+    if (!device->OpenPort())
+        return false;
+
+    isopen = true;
+
+    return true;
+}
+
+void R5000Channel::Close(void)
+{
+    VERBOSE(VB_CHANNEL, LOC + "Close()");
+    if (isopen)
+    {
+        device->ClosePort();
+        isopen = false;
+    }
+}
+
+QString R5000Channel::GetDevice(void) const
+{
+    return videodevice;
+}
+
+bool R5000Channel::SetPowerState(bool on)
+{
+    if (!isopen)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "SetPowerState() called on closed R5000Channel.");
+
+        return false;
+    }
+
+    return device->SetPowerState(on);
+}
+
+R5000Device::PowerState R5000Channel::GetPowerState(void) const
+{
+    if (!isopen)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "GetPowerState() called on closed R5000Channel.");
+
+        return R5000Device::kAVCPowerQueryFailed;
+    }
+
+    return device->GetPowerState();
+}
+
+bool R5000Channel::Retune(void)
+{
+    VERBOSE(VB_CHANNEL, LOC + "Retune()");
+
+    if (R5000Device::kAVCPowerOff == GetPowerState())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "STB is turned off, must be on to retune.");
+
+        return false;
+    }
+
+    if (current_channel)
+        return SetChannelByNumber(current_channel);
+
+    return false;
+}
+
+bool R5000Channel::SetChannelByNumber(int channel)
+{
+    VERBOSE(VB_CHANNEL, QString("SetChannelByNumber(%1)").arg(channel));
+    current_channel = channel;
+
+    if (R5000Device::kAVCPowerOff == GetPowerState())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_WARN +
+                "STB is turned off, must be on to set channel.");
+
+        SetSIStandard("mpeg");
+        SetDTVInfo(0,0,0,0,1);
+
+        return true; // signal monitor will call retune later...
+    }
+
+    if (!device->SetChannel(fw_opts.model, 0, channel))
+        return false;
+
+    SetSIStandard("mpeg");
+    SetDTVInfo(0,0,0,0,1);
+
+    return true;
+}
Index: libs/libmythtv/r5000device.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000device.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,369 @@
+/**
+ *  R5000Device
+ *  Copyright (c) 2008 by Alan Nisota
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// Qt headers
+#include <qdeepcopy.h>
+
+// MythTV headers
+#include "r5000device.h"
+#include "mythcontext.h"
+#include "pespacket.h"
+
+#define LOC      QString("R5kDev: ")
+#define LOC_WARN QString("R5kDev, Warning: ")
+#define LOC_ERR  QString("R5kDev, Error: ")
+
+static void fw_init(QMap<uint64_t,QString> &id_to_model);
+
+QMap<uint64_t,QString> R5000Device::s_id_to_model;
+QMutex                 R5000Device::s_static_lock;
+
+unsigned int r5000_device_tspacket_handler(unsigned char *tspacket, int len, void *callback_data)
+{
+    R5000Device *fw = (R5000Device*) callback_data;
+    if (! fw)
+        return 0;
+    if (len > 0)
+        fw->BroadcastToListeners(tspacket, len);
+    return 1;
+}
+
+
+class R5kPriv
+{
+  public:
+    R5kPriv() :
+        reset_timer_on(false),
+        run_port_handler(false), is_port_handler_running(false),
+        channel(-1),
+        is_streaming(false)
+    {
+    }
+
+    bool             reset_timer_on;
+    MythTimer        reset_timer;
+
+    bool             run_port_handler;
+    bool             is_port_handler_running;
+    QMutex           start_stop_port_handler_lock;
+
+    int              channel;
+
+    bool             is_streaming;
+
+    QDateTime        stop_streaming_timer;
+    pthread_t        port_handler_thread;
+
+    static QMutex           s_lock;
+};
+QMutex          R5kPriv::s_lock;
+
+//callback functions
+void *r5000_device_port_handler_thunk(void *param);
+
+R5000Device::R5000Device(uint64_t guid, uint subunitid, uint speed) :
+    m_guid(guid),           m_subunitid(subunitid),
+    m_speed(speed),
+    m_last_channel(0),      m_last_crc(0),
+    m_buffer_cleared(true), m_open_port_cnt(0),
+    m_lock(false),          m_priv(new R5kPriv())
+{
+  usbdev = NULL;
+}
+
+R5000Device::~R5000Device()
+{
+    if (usbdev)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
+	while(usbdev)
+            ClosePort();
+    }
+
+    if (m_priv)
+    {
+        delete m_priv;
+        m_priv = NULL;
+    }
+}
+
+void R5000Device::AddListener(TSDataListener *listener)
+{
+    if (listener)
+    {
+        vector<TSDataListener*>::iterator it =
+            find(m_listeners.begin(), m_listeners.end(), listener);
+
+        if (it == m_listeners.end())
+            m_listeners.push_back(listener);
+    }
+
+    VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size());
+    if (!m_listeners.empty())
+    {
+        StartStreaming();
+    }
+}
+
+void R5000Device::RemoveListener(TSDataListener *listener)
+{
+    vector<TSDataListener*>::iterator it = m_listeners.end();
+
+    do
+    {
+        it = find(m_listeners.begin(), m_listeners.end(), listener);
+        if (it != m_listeners.end())
+            m_listeners.erase(it);
+    }
+    while (it != m_listeners.end());
+
+    VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size());
+    if (m_listeners.empty())
+    {
+        StopStreaming();
+    }
+}
+
+bool R5000Device::StartStreaming(void)
+{
+    if (m_priv->is_streaming)
+        return m_priv->is_streaming;
+
+    if (! usbdev)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Device not open");
+        return false;
+    }
+    if (r5000_start_stream(usbdev))
+    {
+        m_priv->is_streaming = true;
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming ");
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- done");
+
+    return m_priv->is_streaming;
+}
+
+bool R5000Device::StopStreaming(void)
+{
+    if (m_priv->is_streaming)
+    {
+        VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really");
+
+        m_priv->is_streaming = false;
+
+        r5000_stop_stream(usbdev);
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
+
+    return true;
+}
+
+bool R5000Device::SetPowerState(bool on)
+{
+    QMutexLocker locker(&m_lock);
+    QString cmdStr = (on) ? "on" : "off";
+    VERBOSE(VB_RECORD, LOC + QString("Powering %1").arg(cmdStr));
+    if(r5000_get_power_state(usbdev) != on)
+      r5000_toggle_on_off(usbdev);
+    return true;
+}
+
+R5000Device::PowerState R5000Device::GetPowerState(void)
+{
+    QMutexLocker locker(&m_lock);
+    int on_off;
+
+    VERBOSE(VB_CHANNEL, LOC + "Requesting STB Power State");
+    on_off = r5000_get_power_state(usbdev);
+    VERBOSE(VB_CHANNEL, LOC + (on_off ? "On" : "Off"));
+    return on_off ? kAVCPowerOn : kAVCPowerOff;
+}
+
+bool R5000Device::SetChannel(const QString &panel_model,
+                                uint alt_method, uint channel)
+{
+    VERBOSE(VB_CHANNEL, QString("SetChannel(model %1, alt %2, chan %3)")
+            .arg(panel_model).arg(alt_method).arg(channel));
+
+    QMutexLocker locker(&m_lock);
+    VERBOSE(VB_CHANNEL, "SetChannel() -- locked");
+    r5000_change_channel(usbdev, channel);
+    return true;
+}
+
+void R5000Device::BroadcastToListeners(
+    const unsigned char *data, uint dataSize)
+{
+    if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) &&
+        ((data[1] & 0x1f) == 0) && (data[2] == 0))
+    {
+        ProcessPATPacket(*((const TSPacket*)data));
+    }
+
+    vector<TSDataListener*>::iterator it = m_listeners.begin();
+    for (; it != m_listeners.end(); ++it)
+        (*it)->AddData(data, dataSize);
+}
+
+void R5000Device::SetLastChannel(const uint channel)
+{
+    m_buffer_cleared = (channel == m_last_channel);
+    m_last_channel   = channel;
+
+    VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2")
+            .arg(channel).arg(m_buffer_cleared ? "yes" : "no"));
+}
+
+void R5000Device::ProcessPATPacket(const TSPacket &tspacket)
+{
+    if (!tspacket.TransportError() && !tspacket.ScramplingControl() &&
+        tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID())
+    {
+        PESPacket pes = PESPacket::View(tspacket);
+        uint crc = pes.CalcCRC();
+        m_buffer_cleared |= (crc != m_last_crc);
+        m_last_crc = crc;
+#if 0
+        VERBOSE(VB_RECORD, LOC +
+                QString("ProcessPATPacket: CRC 0x%1 cleared: %2")
+                .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no"));
+#endif
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's");
+    }
+}
+
+QString R5000Device::GetModelName(uint vendor_id, uint model_id)
+{
+    QMutexLocker locker(&s_static_lock);
+/*
+    if (s_id_to_model.empty())
+        fw_init(s_id_to_model);
+
+    QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id];
+
+    if (ret.isEmpty())
+        return "GENERIC";
+*/
+    return "R5000";
+}
+
+bool R5000Device::IsSTBSupported(const QString &panel_model)
+{
+    return true;
+}
+
+bool R5000Device::OpenPort(void)
+{
+    VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread");
+    QMutexLocker mlocker(&m_lock);
+    VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread -- locked");
+    if(usbdev) {
+        m_open_port_cnt++;
+        return true;
+    }
+
+    usbdev = r5000_open(r5000_device_tspacket_handler, this, 0);
+    if(! usbdev)
+        return false;
+
+    VERBOSE(VB_RECORD, LOC + "Starting port handler thread");
+    m_priv->run_port_handler = true;
+    pthread_create(&m_priv->port_handler_thread, NULL,
+                   r5000_device_port_handler_thunk, this);
+
+    VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to start");
+    while (!m_priv->is_port_handler_running)
+    {
+        m_lock.unlock();
+        usleep(5000);
+        m_lock.lock();
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Port handler thread started");
+
+    m_open_port_cnt++;
+
+    return true;
+}
+
+bool R5000Device::ClosePort(void)
+{
+    VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread");
+    QMutexLocker locker(&m_priv->start_stop_port_handler_lock);
+    VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread -- locked");
+
+    QMutexLocker mlocker(&m_lock);
+
+    VERBOSE(VB_RECORD, LOC + "ClosePort()");
+
+    if (m_open_port_cnt < 1)
+        return false;
+
+    m_open_port_cnt--;
+
+    if (m_open_port_cnt != 0)
+        return true;
+
+    if (!usbdev)
+        return false;
+
+    VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to stop");
+    m_priv->run_port_handler = false;
+    while (m_priv->is_port_handler_running)
+    {
+        m_lock.unlock();
+        usleep(5000);
+        m_lock.lock();
+    }
+    VERBOSE(VB_RECORD, LOC + "Joining port handler thread");
+    pthread_join(m_priv->port_handler_thread, NULL);
+
+    r5000_close(usbdev);
+    usbdev = NULL;
+
+    return true;
+}
+
+void *r5000_device_port_handler_thunk(void *param)
+{
+    R5000Device *mon = (R5000Device*) param;
+    mon->RunPortHandler();
+    return NULL;
+}
+
+void R5000Device::RunPortHandler(void)
+{
+    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start");
+    m_lock.lock();
+    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock");
+    m_priv->is_port_handler_running = true;
+    m_lock.unlock();
+
+    while (m_priv->run_port_handler)
+    {
+        if (m_priv->is_streaming) {
+            // This will timeout after 10ms regardless of data availability
+            r5000_loop_iterate(usbdev, 10);
+        } else {
+            usleep(10000);
+        }
+    }
+
+    m_lock.lock();
+    m_priv->is_port_handler_running = false;
+    m_lock.unlock();
+    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end");
+}
Index: libs/libmythtv/r5000recorder.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000recorder.cpp	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,238 @@
+/**
+ *  R5000Recorder
+ *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// MythTV includes
+#include "r5000recorder.h"
+#include "r5000channel.h"
+#include "mythcontext.h"
+#include "mpegtables.h"
+#include "mpegstreamdata.h"
+#include "tv_rec.h"
+
+#define LOC QString("R5000RecBase(%1): ").arg(channel->GetDevice())
+#define LOC_ERR QString("R5000RecBase(%1), Error: ").arg(channel->GetDevice())
+
+R5000Recorder::R5000Recorder(TVRec *rec, R5000Channel *chan) :
+    DTVRecorder(rec), _mpeg_stream_data(NULL),
+    channel(chan), isopen(false)
+{
+}
+
+R5000Recorder::~R5000Recorder()
+{
+    SetStreamData(NULL);
+    Close();
+}
+
+bool R5000Recorder::Open(void)
+{
+    if (!isopen)
+        isopen = channel->GetR5000Device()->OpenPort();
+
+    return isopen;
+}
+
+void R5000Recorder::Close(void)
+{
+    if (isopen)
+    {
+        channel->GetR5000Device()->ClosePort();
+        isopen = false;
+    }
+}
+
+void R5000Recorder::StartStreaming(void)
+{
+    channel->GetR5000Device()->AddListener(this);
+}
+
+void R5000Recorder::StopStreaming(void)
+{
+    channel->GetR5000Device()->RemoveListener(this);
+}
+
+void R5000Recorder::StartRecording(void)
+{
+    VERBOSE(VB_RECORD, LOC + "StartRecording");
+
+    if (!Open())
+    {
+        _error = true;
+        return;
+    }
+
+    _request_recording = true;
+    _recording = true;
+
+    StartStreaming();
+
+    while (_request_recording)
+    {
+        if (!PauseAndWait())
+            usleep(50 * 1000);
+    }
+
+    StopStreaming();
+    FinishRecording();
+
+    _recording = false;
+}
+
+void R5000Recorder::AddData(const unsigned char *data, uint len)
+{
+    uint bufsz = buffer.size();
+    if ((SYNC_BYTE == data[0]) && (TSPacket::SIZE == len) &&
+        (TSPacket::SIZE > bufsz))
+    {
+        if (bufsz)
+            buffer.clear();
+
+        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data)));
+        return;
+    }
+
+    buffer.insert(buffer.end(), data, data + len);
+    bufsz += len;
+
+    int sync_at = -1;
+    for (uint i = 0; (i < bufsz) && (sync_at < 0); i++)
+    {
+        if (buffer[i] == SYNC_BYTE)
+            sync_at = i;
+    }
+
+    if (sync_at < 0)
+        return;
+
+    if (bufsz < 30 * TSPacket::SIZE)
+        return; // build up a little buffer
+
+    while (sync_at + TSPacket::SIZE < bufsz)
+    {
+        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(
+                              &buffer[0] + sync_at)));
+
+        sync_at += TSPacket::SIZE;
+    }
+
+    buffer.erase(buffer.begin(), buffer.begin() + sync_at);
+
+    return;
+}
+
+void R5000Recorder::ProcessTSPacket(const TSPacket &tspacket)
+{
+    if (tspacket.TransportError())
+        return;
+
+    if (tspacket.ScramplingControl())
+        return;
+
+    if (tspacket.HasAdaptationField())
+        GetStreamData()->HandleAdaptationFieldControl(&tspacket);
+
+    if (tspacket.HasPayload())
+    {
+        const unsigned int lpid = tspacket.PID();
+        // Pass or reject packets based on PID, and parse info from them
+        if (lpid == GetStreamData()->VideoPIDSingleProgram())
+        {
+            _buffer_packets = !FindMPEG2Keyframes(&tspacket);
+            BufferedWrite(tspacket);
+        }
+        else if (GetStreamData()->IsAudioPID(lpid))
+        {
+            _buffer_packets = !FindAudioKeyframes(&tspacket);
+            BufferedWrite(tspacket);
+        }
+        else if (GetStreamData()->IsListeningPID(lpid))
+            GetStreamData()->HandleTSTables(&tspacket);
+        else if (GetStreamData()->IsWritingPID(lpid))
+            BufferedWrite(tspacket);
+    }
+}
+
+void R5000Recorder::SetOptionsFromProfile(RecordingProfile *profile,
+                                                 const QString &videodev,
+                                                 const QString &audiodev,
+                                                 const QString &vbidev)
+{
+    (void)videodev;
+    (void)audiodev;
+    (void)vbidev;
+    (void)profile;
+}
+
+// documented in recorderbase.cpp
+bool R5000Recorder::PauseAndWait(int timeout)
+{
+    if (request_pause)
+    {
+        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause");
+        if (!paused)
+        {
+            StopStreaming();
+            paused = true;
+            pauseWait.wakeAll();
+            if (tvrec)
+                tvrec->RecorderPaused();
+        }
+        unpauseWait.wait(timeout);
+    }
+    if (!request_pause && paused)
+    {
+        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause");
+        StartStreaming();
+        paused = false;
+    }
+    return paused;
+}
+
+void R5000Recorder::SetStreamData(MPEGStreamData *data)
+{
+    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- begin");
+    if (data == _mpeg_stream_data)
+    {
+        VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 0");
+        return;
+    }
+
+    MPEGStreamData *old_data = _mpeg_stream_data;
+    _mpeg_stream_data = data;
+    if (old_data)
+        delete old_data;
+
+    if (data)
+    {
+        data->AddMPEGSPListener(this);
+
+        if (data->DesiredProgram() >= 0)
+            data->SetDesiredProgram(data->DesiredProgram());
+    }
+    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 1");
+}
+
+void R5000Recorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
+{
+    if (!pat) {
+        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPAT(NULL)");
+        return;
+    }
+    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
+    pat->tsheader()->SetContinuityCounter(next);
+    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));
+}
+
+void R5000Recorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
+{
+    if (!pmt) {
+        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)");
+        return;
+    }
+    int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
+    pmt->tsheader()->SetContinuityCounter(next);
+    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));
+}
Index: libs/libmythtv/r5000signalmonitor.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000signalmonitor.cpp	2008-02-22 15:38:19.000000000 -0800
@@ -0,0 +1,312 @@
+// -*- Mode: c++ -*-
+// Copyright (c) 2006, Daniel Thor Kristjansson
+
+#include <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+
+#include "mythcontext.h"
+#include "mythdbcon.h"
+#include "atscstreamdata.h"
+#include "mpegtables.h"
+#include "atsctables.h"
+#include "r5000channel.h"
+#include "r5000signalmonitor.h"
+
+#define LOC QString("R5kSM(%1): ").arg(channel->GetDevice())
+#define LOC_WARN QString("R5kSM(%1), Warning: ").arg(channel->GetDevice())
+#define LOC_ERR QString("R5kSM(%1), Error: ").arg(channel->GetDevice())
+
+const uint R5000SignalMonitor::kPowerTimeout  = 3000; /* ms */
+const uint R5000SignalMonitor::kBufferTimeout = 5000; /* ms */
+
+QMap<void*,uint> R5000SignalMonitor::pat_keys;
+QMutex           R5000SignalMonitor::pat_keys_lock;
+
+/** \fn R5000SignalMonitor::R5000SignalMonitor(int,R5000Channel*,uint,const char*)
+ *  \brief Initializes signal lock and signal values.
+ *
+ *   Start() must be called to actually begin continuous
+ *   signal monitoring. The timeout is set to 3 seconds,
+ *   and the signal threshold is initialized to 0%.
+ *
+ *  \param db_cardnum Recorder number to monitor,
+ *                    if this is less than 0, SIGNAL events will not be
+ *                    sent to the frontend even if SetNotifyFrontend(true)
+ *                    is called.
+ *  \param _channel R5000Channel for card
+ *  \param _flags   Flags to start with
+ *  \param _name    Name for Qt signal debugging
+ */
+R5000SignalMonitor::R5000SignalMonitor(
+    int db_cardnum,
+    R5000Channel *_channel,
+    uint64_t _flags, const char *_name) :
+    DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
+    dtvMonitorRunning(false),
+    stb_needs_retune(true),
+    stb_needs_to_wait_for_pat(false),
+    stb_needs_to_wait_for_power(false)
+{
+    VERBOSE(VB_CHANNEL, LOC + "ctor");
+
+    signalStrength.SetThreshold(65);
+
+    AddFlags(kDTVSigMon_WaitForSig);
+
+    stb_needs_retune =
+        (R5000Device::kAVCPowerOff == _channel->GetPowerState());
+}
+
+/** \fn R5000SignalMonitor::~R5000SignalMonitor()
+ *  \brief Stops signal monitoring and table monitoring threads.
+ */
+R5000SignalMonitor::~R5000SignalMonitor()
+{
+    VERBOSE(VB_CHANNEL, LOC + "dtor");
+    Stop();
+}
+
+void R5000SignalMonitor::deleteLater(void)
+{
+    disconnect(); // disconnect signals we may be sending...
+    Stop();
+    DTVSignalMonitor::deleteLater();
+}
+
+/** \fn R5000SignalMonitor::Stop(void)
+ *  \brief Stop signal monitoring and table monitoring threads.
+ */
+void R5000SignalMonitor::Stop(void)
+{
+    VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
+    SignalMonitor::Stop();
+    if (dtvMonitorRunning)
+    {
+        dtvMonitorRunning = false;
+        pthread_join(table_monitor_thread, NULL);
+    }
+    VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
+}
+
+void R5000SignalMonitor::HandlePAT(const ProgramAssociationTable *pat)
+{
+    AddFlags(kDTVSigMon_PATSeen);
+
+    R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel);
+    bool crc_bogus = !fwchan->GetR5000Device()->IsSTBBufferCleared();
+    if (crc_bogus && stb_needs_to_wait_for_pat &&
+        (stb_wait_for_pat_timer.elapsed() < (int)kBufferTimeout))
+    {
+        VERBOSE(VB_CHANNEL, LOC + "HandlePAT() ignoring PAT");
+        uint tsid = pat->TransportStreamID();
+        GetStreamData()->SetVersionPAT(tsid, -1,0);
+        return;
+    }
+
+    if (crc_bogus && stb_needs_to_wait_for_pat)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_WARN + "Wait for valid PAT timed out");
+        stb_needs_to_wait_for_pat = false;
+    }
+
+    DTVSignalMonitor::HandlePAT(pat);
+}
+
+void R5000SignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt)
+{
+    VERBOSE(VB_CHANNEL, LOC + "HandlePMT()");
+
+    AddFlags(kDTVSigMon_PMTSeen);
+
+    if (!HasFlags(kDTVSigMon_PATMatch))
+    {
+        GetStreamData()->SetVersionPMT(pnum, -1,0);
+        VERBOSE(VB_CHANNEL, LOC + "HandlePMT() ignoring PMT");
+        return;
+    }
+
+    DTVSignalMonitor::HandlePMT(pnum, pmt);
+}
+
+void *R5000SignalMonitor::TableMonitorThread(void *param)
+{
+    R5000SignalMonitor *mon = (R5000SignalMonitor*) param;
+    mon->RunTableMonitor();
+    return NULL;
+}
+
+void R5000SignalMonitor::RunTableMonitor(void)
+{
+    stb_needs_to_wait_for_pat = true;
+    stb_wait_for_pat_timer.start();
+    dtvMonitorRunning = true;
+
+    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin");
+
+    R5000Channel *lchan = dynamic_cast<R5000Channel*>(channel);
+    if (!lchan)
+    {
+        VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end");
+        dtvMonitorRunning = false;
+        return;
+    }
+
+    R5000Device *dev = lchan->GetR5000Device();
+
+    dev->OpenPort();
+    dev->AddListener(this);
+
+    while (dtvMonitorRunning && GetStreamData())
+        usleep(100000);
+
+    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown ");
+
+    dev->RemoveListener(this);
+    dev->ClosePort();
+
+    dtvMonitorRunning = false;
+
+    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
+}
+
+void R5000SignalMonitor::AddData(const unsigned char *data, uint len)
+{
+    if (!dtvMonitorRunning)
+        return;
+
+    if (GetStreamData())
+        GetStreamData()->ProcessData((unsigned char *)data, len);
+}
+
+/** \fn R5000SignalMonitor::UpdateValues(void)
+ *  \brief Fills in frontend stats and emits status Qt signals.
+ *
+ *   This function uses five ioctl's FE_READ_SNR, FE_READ_SIGNAL_STRENGTH
+ *   FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain
+ *   statistics from the frontend.
+ *
+ *   This is automatically called by MonitorLoop(), after Start()
+ *   has been used to start the signal monitoring thread.
+ */
+void R5000SignalMonitor::UpdateValues(void)
+{
+    if (!running || exit)
+        return;
+
+    if (dtvMonitorRunning)
+    {
+        EmitR5000Signals();
+        if (IsAllGood())
+            emit AllGood();
+        // TODO dtv signals...
+
+        update_done = true;
+        return;
+    }
+
+    if (stb_needs_to_wait_for_power &&
+        (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout))
+    {
+        return;
+    }
+    stb_needs_to_wait_for_power = false;
+
+    R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel);
+
+    if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch))
+    {
+        bool retried = false;
+        while (true)
+        {
+            R5000Device::PowerState power = fwchan->GetPowerState();
+            if (R5000Device::kAVCPowerOn == power)
+            {
+                AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
+            }
+            else if (R5000Device::kAVCPowerOff == power)
+            {
+                AddFlags(kFWSigMon_PowerSeen);
+                fwchan->SetPowerState(true);
+                stb_wait_for_power_timer.start();
+                stb_needs_to_wait_for_power = true;
+            }
+            else
+            {
+                bool qfailed = (R5000Device::kAVCPowerQueryFailed == power);
+                if (qfailed && !retried)
+                {
+                    retried = true;
+                    continue;
+                }
+
+                VERBOSE(VB_RECORD, "Can't determine if STB is power on, "
+                        "assuming it is...");
+                AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
+            }
+            break;
+        }
+    }
+
+    bool isLocked = !HasFlags(kFWSigMon_WaitForPower) ||
+        HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch);
+
+    if (isLocked && stb_needs_retune)
+    {
+        fwchan->Retune();
+        isLocked = stb_needs_retune = false;
+    }
+
+    // Set SignalMonitorValues from info from card.
+    {
+        QMutexLocker locker(&statusLock);
+        signalStrength.SetValue(isLocked ? 100 : 0);
+        signalLock.SetValue(isLocked ? 1 : 0);
+    }
+
+    EmitR5000Signals();
+    if (IsAllGood())
+        emit AllGood();
+
+    // Start table monitoring if we are waiting on any table
+    // and we have a lock.
+    if (isLocked && GetStreamData() &&
+        HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT |
+                   kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
+                   kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
+    {
+        pthread_create(&table_monitor_thread, NULL,
+                       TableMonitorThread, this);
+
+        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
+                "Waiting for table monitor to start");
+
+        while (!dtvMonitorRunning)
+            usleep(50);
+
+        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
+                "Table monitor started");
+    }
+
+    update_done = true;
+}
+
+#define EMIT(SIGNAL_FUNC, SIGNAL_VAL) \
+    do { statusLock.lock(); \
+         SignalMonitorValue val = SIGNAL_VAL; \
+         statusLock.unlock(); \
+         emit SIGNAL_FUNC(val); } while (false)
+
+/** \fn R5000SignalMonitor::EmitR5000Signals(void)
+ *  \brief Emits signals for lock, signal strength, etc.
+ */
+void R5000SignalMonitor::EmitR5000Signals(void)
+{
+    // Emit signals..
+    EMIT(StatusSignalLock, signalLock);
+    if (HasFlags(kDTVSigMon_WaitForSig))
+        EMIT(StatusSignalStrength, signalStrength);
+}
+
+#undef EMIT
Index: libs/libmythtv/r5000channel.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000channel.h	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,51 @@
+/**
+ *  R5000Channel
+ *  Copyright (c) 2008 by Alan Nisota
+ *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef _R5000CHANNEL_H_
+#define _R5000CHANNEL_H_
+
+#include "tv_rec.h"
+#include "dtvchannel.h"
+#include "r5000device.h"
+
+class R5000Channel : public DTVChannel
+{
+  public:
+    R5000Channel(TVRec *parent, const QString &videodevice,
+                    const FireWireDBOptions &firewire_opts);
+    ~R5000Channel() { Close(); }
+
+    // Commands
+    virtual bool Open(void);
+    virtual void Close(void);
+
+    virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/)
+        { return false; }
+    virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/)
+        { return false; }
+    virtual bool Retune(void);
+
+    // Sets
+    virtual bool SetChannelByString(const QString &chan);
+    virtual bool SetChannelByNumber(int channel);
+    virtual bool SetPowerState(bool on);
+
+    // Gets
+    virtual bool IsOpen(void) const { return isopen; }
+    virtual R5000Device::PowerState GetPowerState(void) const;
+    virtual QString GetDevice(void) const;
+    virtual R5000Device *GetR5000Device(void) { return device; }
+
+  protected:
+    QString            videodevice;
+    FireWireDBOptions  fw_opts;
+    R5000Device    *device;
+    uint               current_channel;
+    bool               isopen;
+};
+
+#endif // _FIREWIRECHANNEL_H_
Index: libs/libmythtv/r5000device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000device.h	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,254 @@
+/**
+ *  R5000Device
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef _R5000_DEVICE_H_
+#define _R5000_DEVICE_H_
+
+// C++ headers
+#include <vector>
+using namespace std;
+
+// Qt headers
+#include <qstring.h>
+#include <qmutex.h>
+
+// MythTV headers
+#include "streamlisteners.h"
+
+extern "C" {
+#include "r5000/r5000.h"
+}
+
+class TSPacket;
+class R5kPriv;
+class R5000Device
+{
+  public:
+
+    // Public enums
+    typedef enum
+    {
+        kAVCPowerOn,
+        kAVCPowerOff,
+        kAVCPowerUnknown,
+        kAVCPowerQueryFailed,
+    } PowerState;
+
+    // AVC commands
+    typedef enum
+    {
+        kAVCControlCommand         = 0x00,
+        kAVCStatusInquiryCommand   = 0x01,
+        kAVCSpecificInquiryCommand = 0x02,
+        kAVCNotifyCommand          = 0x03,
+        kAVCGeneralInquiryCommand  = 0x04,
+
+        kAVCNotImplementedStatus   = 0x08,
+        kAVCAcceptedStatus         = 0x09,
+        kAVCRejectedStatus         = 0x0a,
+        kAVCInTransitionStatus     = 0x0b,
+        kAVCImplementedStatus      = 0x0c,
+        kAVCChangedStatus          = 0x0d,
+
+        kAVCInterimStatus          = 0x0f,
+        kAVCResponseImplemented    = 0x0c,
+    } IEEE1394Command;
+
+    // AVC unit addresses
+    typedef enum
+    {
+        kAVCSubunitId0                = 0x00,
+        kAVCSubunitId1                = 0x01,
+        kAVCSubunitId2                = 0x02,
+        kAVCSubunitId3                = 0x03,
+        kAVCSubunitId4                = 0x04,
+        kAVCSubunitIdExtended         = 0x05,
+        kAVCSubunitIdIgnore           = 0x07,
+
+        kAVCSubunitTypeVideoMonitor   = (0x00 << 3),
+        kAVCSubunitTypeAudio          = (0x01 << 3),
+        kAVCSubunitTypePrinter        = (0x02 << 3),
+        kAVCSubunitTypeDiscRecorder   = (0x03 << 3),
+        kAVCSubunitTypeTapeRecorder   = (0x04 << 3),
+        kAVCSubunitTypeTuner          = (0x05 << 3),
+        kAVCSubunitTypeCA             = (0x06 << 3),
+        kAVCSubunitTypeVideoCamera    = (0x07 << 3),
+        kAVCSubunitTypePanel          = (0x09 << 3),
+        kAVCSubunitTypeBulletinBoard  = (0x0a << 3),
+        kAVCSubunitTypeCameraStorage  = (0x0b << 3),
+        kAVCSubunitTypeMusic          = (0x0c << 3),
+        kAVCSubunitTypeVendorUnique   = (0x1c << 3),
+        kAVCSubunitTypeExtended       = (0x1e << 3),
+        kAVCSubunitTypeUnit           = (0x1f << 3),
+    } IEEE1394UnitAddress;
+
+    // AVC opcode
+    typedef enum
+    {
+        // Unit
+        kAVCUnitPlugInfoOpcode               = 0x02,
+        kAVCUnitDigitalOutputOpcode          = 0x10,
+        kAVCUnitDigitalInputOpcode           = 0x11,
+        kAVCUnitChannelUsageOpcode           = 0x12,
+        kAVCUnitOutputPlugSignalFormatOpcode = 0x18,
+        kAVCUnitInputPlugSignalFormatOpcode  = 0x19,
+        kAVCUnitConnectAVOpcode              = 0x20,
+        kAVCUnitDisconnectAVOpcode           = 0x21,
+        kAVCUnitConnectionsOpcode            = 0x22,
+        kAVCUnitConnectOpcode                = 0x24,
+        kAVCUnitDisconnectOpcode             = 0x25,
+        kAVCUnitUnitInfoOpcode               = 0x30,
+        kAVCUnitSubunitInfoOpcode            = 0x31,
+        kAVCUnitSignalSourceOpcode           = 0x1a,
+        kAVCUnitPowerOpcode                  = 0xb2,
+
+        // Common Unit + Subunit
+        kAVCCommonOpenDescriptorOpcode       = 0x08,
+        kAVCCommonReadDescriptorOpcode       = 0x09,
+        kAVCCommonWriteDescriptorOpcode      = 0x0A,
+        kAVCCommonSearchDescriptorOpcode     = 0x0B,
+        kAVCCommonObjectNumberSelectOpcode   = 0x0D,
+        kAVCCommonPowerOpcode                = 0xB2,
+        kAVCCommonReserveOpcode              = 0x01,
+        kAVCCommonPlugInfoOpcode             = 0x02,
+        kAVCCommonVendorDependentOpcode      = 0x00,
+
+        // Panel
+        kAVCPanelPassThrough                 = 0x7c,
+    } IEEE1394Opcode;
+
+    // AVC param 0
+    typedef enum
+    {
+        kAVCPowerStateOn           = 0x70,
+        kAVCPowerStateOff          = 0x60,
+        kAVCPowerStateQuery        = 0x7f,
+    } IEEE1394UnitPowerParam0;
+
+    typedef enum
+    {
+        kAVCPanelKeySelect          = 0x00,
+        kAVCPanelKeyUp              = 0x01,
+        kAVCPanelKeyDown            = 0x02,
+        kAVCPanelKeyLeft            = 0x03,
+        kAVCPanelKeyRight           = 0x04,
+        kAVCPanelKeyRightUp         = 0x05,
+        kAVCPanelKeyRightDown       = 0x06,
+        kAVCPanelKeyLeftUp          = 0x07,
+        kAVCPanelKeyLeftDown        = 0x08,
+        kAVCPanelKeyRootMenu        = 0x09,
+        kAVCPanelKeySetupMenu       = 0x0A,
+        kAVCPanelKeyContentsMenu    = 0x0B,
+        kAVCPanelKeyFavoriteMenu    = 0x0C,
+        kAVCPanelKeyExit            = 0x0D,
+
+        kAVCPanelKey0               = 0x20,
+        kAVCPanelKey1               = 0x21,
+        kAVCPanelKey2               = 0x22,
+        kAVCPanelKey3               = 0x23,
+        kAVCPanelKey4               = 0x24,
+        kAVCPanelKey5               = 0x25,
+        kAVCPanelKey6               = 0x26,
+        kAVCPanelKey7               = 0x27,
+        kAVCPanelKey8               = 0x28,
+        kAVCPanelKey9               = 0x29,
+        kAVCPanelKeyDot             = 0x2A,
+        kAVCPanelKeyEnter           = 0x2B,
+        kAVCPanelKeyClear           = 0x2C,
+
+        kAVCPanelKeyChannelUp       = 0x30,
+        kAVCPanelKeyChannelDown     = 0x31,
+        kAVCPanelKeyPreviousChannel = 0x32,
+        kAVCPanelKeySoundSelect     = 0x33,
+        kAVCPanelKeyInputSelect     = 0x34,
+        kAVCPanelKeyDisplayInfo     = 0x35,
+        kAVCPanelKeyHelp            = 0x36,
+        kAVCPanelKeyPageUp          = 0x37,
+        kAVCPanelKeyPageDown        = 0x38,
+
+        kAVCPanelKeyPower           = 0x40,
+        kAVCPanelKeyVolumeUp        = 0x41,
+        kAVCPanelKeyVolumeDown      = 0x42,
+        kAVCPanelKeyMute            = 0x43,
+        kAVCPanelKeyPlay            = 0x44,
+        kAVCPanelKeyStop            = 0x45,
+        kAVCPanelKeyPause           = 0x46,
+        kAVCPanelKeyRecord          = 0x47,
+        kAVCPanelKeyRewind          = 0x48,
+        kAVCPanelKeyFastForward     = 0x49,
+        kAVCPanelKeyEject           = 0x4a,
+        kAVCPanelKeyForward         = 0x4b,
+        kAVCPanelKeyBackward        = 0x4c,
+
+        kAVCPanelKeyAngle           = 0x50,
+        kAVCPanelKeySubPicture      = 0x51,
+
+        kAVCPanelKeyTuneFunction    = 0x67,
+
+        kAVCPanelKeyPress           = 0x00,
+        kAVCPanelKeyRelease         = 0x80,
+
+    } IEEE1394PanelPassThroughParam0;
+
+    R5000Device(uint64_t guid, uint subunitid, uint speed);
+    ~R5000Device();
+
+    bool OpenPort(void);
+    bool ClosePort(void);
+    void RunPortHandler(void);
+
+    // Commands
+    virtual bool ResetBus(void) { return false; }
+
+    virtual void AddListener(TSDataListener*);
+    virtual void RemoveListener(TSDataListener*);
+
+    // Sets
+    virtual bool SetPowerState(bool on);
+    virtual bool SetChannel(const QString &panel_model,
+                            uint alt_method, uint channel);
+
+    // Gets
+    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
+
+    // non-const Gets
+    virtual PowerState GetPowerState(void);
+
+    // Statics
+    static bool IsSTBSupported(const QString &model);
+    static QString GetModelName(uint vendorid, uint modelid);
+    void BroadcastToListeners(
+        const unsigned char *data, uint dataSize);
+
+  protected:
+
+    bool GetSubunitInfo(uint8_t table[32]);
+
+    void SetLastChannel(uint channel);
+    void ProcessPATPacket(const TSPacket&);
+    bool StartStreaming(void);
+    bool StopStreaming(void);
+
+    uint64_t                 m_guid;
+    uint                     m_subunitid;
+    uint                     m_speed;
+    uint                     m_last_channel;
+    uint                     m_last_crc;
+    bool                     m_buffer_cleared;
+
+    uint                     m_open_port_cnt;
+    vector<TSDataListener*>  m_listeners;
+    mutable QMutex           m_lock;
+
+    /// Vendor ID + Model ID to R5000Device STB model string
+    static QMap<uint64_t,QString> s_id_to_model;
+    static QMutex                 s_static_lock;
+private:
+    r5kdev_t                 *usbdev;
+    R5kPriv                  *m_priv;
+};
+
+#endif // _FIREWIRE_DEVICE_H_
Index: libs/libmythtv/r5000recorder.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000recorder.h	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,72 @@
+/**
+ *  R5000Recorder
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef _R5000RECORDER_H_
+#define _R5000RECORDER_H_
+
+// MythTV headers
+#include "dtvrecorder.h"
+#include "tspacket.h"
+#include "streamlisteners.h"
+
+class TVRec;
+class R5000Channel;
+
+/** \class R5000Recorder
+ *  \brief This is a specialization of DTVRecorder used to
+ *         handle DVB and ATSC streams from a firewire input.
+ *
+ *  \sa DTVRecorder
+ */
+class R5000Recorder : public DTVRecorder,
+                         public MPEGSingleProgramStreamListener,
+                         public TSDataListener
+{
+    friend class MPEGStreamData;
+    friend class TSPacketProcessor;
+
+  public:
+    R5000Recorder(TVRec *rec, R5000Channel *chan);
+    virtual ~R5000Recorder();
+
+    // Commands
+    bool Open(void);
+    void Close(void);
+
+    void StartStreaming(void);
+    void StopStreaming(void);
+
+    void StartRecording(void);
+    bool PauseAndWait(int timeout = 100);
+
+    void AddData(const unsigned char *data, uint dataSize);
+    void ProcessTSPacket(const TSPacket &tspacket);
+
+    // Sets
+    void SetOptionsFromProfile(RecordingProfile *profile,
+                               const QString &videodev,
+                               const QString &audiodev,
+                               const QString &vbidev);
+    void SetStreamData(MPEGStreamData*);
+
+    // Gets
+    MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; }
+
+    // MPEG Single Program
+    void HandleSingleProgramPAT(ProgramAssociationTable*);
+    void HandleSingleProgramPMT(ProgramMapTable*);
+
+  protected:
+    R5000Recorder(TVRec *rec);
+
+  private:
+    MPEGStreamData        *_mpeg_stream_data;
+    R5000Channel       *channel;
+    bool                   isopen;
+    vector<unsigned char>  buffer;
+};
+
+#endif //  _R5000RECORDER_H_
Index: libs/libmythtv/r5000signalmonitor.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000signalmonitor.h	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,67 @@
+// -*- Mode: c++ -*-
+
+#ifndef _R5000SIGNALMONITOR_H_
+#define _R5000SIGNALMONITOR_H_
+
+#include <qmap.h>
+#include <qmutex.h>
+#include <qdatetime.h>
+
+#include "dtvsignalmonitor.h"
+#include "firewiredevice.h"
+#include "util.h"
+
+class R5000Channel;
+
+class R5000SignalMonitor : public DTVSignalMonitor, public TSDataListener
+{
+    Q_OBJECT
+
+  public:
+    R5000SignalMonitor(int db_cardnum, R5000Channel *_channel,
+                          uint64_t _flags = kFWSigMon_WaitForPower,
+                          const char *_name = "R5000SignalMonitor");
+
+    virtual void HandlePAT(const ProgramAssociationTable*);
+    virtual void HandlePMT(uint, const ProgramMapTable*);
+
+    void Stop(void);
+
+  public slots:
+    void deleteLater(void);
+
+  protected:
+    R5000SignalMonitor(void);
+    R5000SignalMonitor(const R5000SignalMonitor&);
+    virtual ~R5000SignalMonitor();
+
+    virtual void UpdateValues(void);
+    void EmitR5000Signals(void);
+
+    static void *TableMonitorThread(void *param);
+    void RunTableMonitor(void);
+
+    bool SupportsTSMonitoring(void);
+
+    void AddData(const unsigned char *data, uint dataSize);
+
+  public:
+    static const uint kPowerTimeout;
+    static const uint kBufferTimeout;
+
+  protected:
+    bool               dtvMonitorRunning;
+    pthread_t          table_monitor_thread;
+    bool               stb_needs_retune;
+    bool               stb_needs_to_wait_for_pat;
+    bool               stb_needs_to_wait_for_power;
+    MythTimer          stb_wait_for_pat_timer;
+    MythTimer          stb_wait_for_power_timer;
+
+    vector<unsigned char> buffer;
+
+    static QMap<void*,uint> pat_keys;
+    static QMutex           pat_keys_lock;
+};
+
+#endif // _R5000SIGNALMONITOR_H_
Index: libs/libmythtv/r5000/libusb_augment.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/libusb_augment.c	2008-02-22 15:38:00.000000000 -0800
@@ -0,0 +1,297 @@
+// 2005-10-19/lindi: downloaded from http://www.gaesi.org/~nmct/cvista/cvista/
+
+// libusb_augment.c
+// $Revision$
+// $Date$
+
+// Hopefully, the functions in this file will become part of libusb.
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <usb.h>
+#include <linux/usbdevice_fs.h>
+#include <string.h>
+#include <signal.h>
+#define LIBUSB_AUGMENT
+#include "libusb_augment.h"
+
+// Taken from libusb file usbi.h because usb.h
+// hides the definition of usb_dev_handle.
+extern int usb_debug;
+
+struct usb_dev_handle {
+  int fd;
+
+  struct usb_bus *bus;
+  struct usb_device *device;
+
+  int config;
+  int interface;
+  int altsetting;
+
+  /* Added by RMT so implementations can store other per-open-device data */
+  void *impl_info;
+};
+
+// Taken from libusb file error.h to supply error handling macro definition.
+typedef enum {
+  USB_ERROR_TYPE_NONE = 0,
+  USB_ERROR_TYPE_STRING,
+  USB_ERROR_TYPE_ERRNO,
+} usb_error_type_t;
+
+extern char usb_error_str[1024];
+extern usb_error_type_t usb_error_type;
+
+#define USB_ERROR_STR(format, args...) \
+	do { \
+	  usb_error_type = USB_ERROR_TYPE_STRING; \
+	  snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+          if (usb_debug >= 2) \
+            fprintf(stderr, "USB error: %s\n", usb_error_str); \
+	} while (0)
+
+static int urb_signr = 0;
+void (*urb_completion_callback)(struct usbdevfs_urb *) = NULL;
+#define USB_ASYNC_COMPLETION_SIGNAL (SIGRTMIN + 5)
+
+void urb_completion_handler(int signum, siginfo_t *info, void *context)
+{
+   struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr;
+   struct usbdevfs_urb *context1;
+   usb_dev_handle *dev = (usb_dev_handle *)urb->usercontext;
+   int ret;
+   if (info->si_code != SI_ASYNCIO ||
+       info->si_signo != USB_ASYNC_COMPLETION_SIGNAL) {
+       return;
+   }
+   if(info->si_errno != 0) {
+     USB_ERROR_STR("Async URB Completion failed: %s", strerror(info->si_errno));
+     return;
+   }
+   ret = ioctl(dev->fd, USBDEVFS_REAPURB, &context1);
+   if(ret  < 0) {
+     USB_ERROR_STR("Failed to read URB: %s", strerror(-ret));
+     return;
+   }
+   if(context1 != urb) {
+     USB_ERROR_STR("Reaped unexpected urb");
+     return;
+   }
+   if(urb_completion_callback)
+     urb_completion_callback(urb);
+}
+
+int usbdevfs_urb_signal_completion(void (*cb)( struct usbdevfs_urb *))
+{
+  urb_completion_callback = cb;
+  urb_signr = USB_ASYNC_COMPLETION_SIGNAL;
+  struct sigaction usb_linux_sa;
+  usb_linux_sa.sa_sigaction = urb_completion_handler;
+  sigfillset(&usb_linux_sa.sa_mask);
+  usb_linux_sa.sa_flags = SA_SIGINFO;
+  usb_linux_sa.sa_flags |= SA_ONSTACK;
+  sigaction(USB_ASYNC_COMPLETION_SIGNAL, &usb_linux_sa, NULL);
+  return 0;
+}
+
+struct usbdevfs_urb *usb_bulk_setup(
+                struct usbdevfs_urb *iso_urb, // URB pointer-pointer.
+		unsigned char ep,  // Device endpoint.
+		char *bytes,       // Data buffer pointer.
+		int size) {        // Size of the buffer.
+  struct usbdevfs_urb *local_urb;
+
+  // No more than 16384 bytes can be transferred at a time.
+  if (size > 16384) {
+    USB_ERROR_STR("error on transfer size: %s", strerror(EINVAL));
+    return NULL;
+  }
+  local_urb = iso_urb;
+  if (!local_urb) {
+    local_urb = (struct usbdevfs_urb *) calloc(1, sizeof(struct usbdevfs_urb));
+    if (!local_urb) {
+      USB_ERROR_STR("error on packet size: %s", strerror(EINVAL));
+      return NULL;
+    }
+  }
+  local_urb->type = USBDEVFS_URB_TYPE_BULK;
+  local_urb->endpoint = ep;
+  local_urb->status = 0;
+  local_urb->flags = 0;
+  local_urb->buffer = bytes;
+  local_urb->buffer_length = size;
+  local_urb->actual_length = 0;
+  local_urb->start_frame = 0;
+  local_urb->number_of_packets = 0;
+  local_urb->error_count = 0;
+  local_urb->signr = urb_signr;
+  local_urb->usercontext = (void *) 0;
+  return local_urb;
+}
+// Reading and writing are the same except for the endpoint
+int usb_isochronous_setup(struct usbdevfs_urb **iso_urb, // URB pointer-pointer.
+			  unsigned char ep,  // Device endpoint.
+			  int pktsize,       // Endpoint packet size.
+			  char *bytes,       // Data buffer pointer.
+			  int size) {        // Size of the buffer.
+  struct usbdevfs_urb *local_urb;
+  // int ret
+  // was unused /lindi
+  int pktcount, fullpkts, partpktsize, packets, urb_size;
+
+  // No more than 32768 bytes can be transferred at a time.
+  if (size > 32768) {
+    USB_ERROR_STR("error on transfer size: %s", strerror(EINVAL));
+    return -EINVAL;
+  }
+
+  // Determine the number of packets that need to be created based upon the
+  // amount of data to be transferred, and the maximum packet size of the
+  // endpoint.
+
+  // Find integral number of full packets.
+  //fprintf(stderr, "buf size: %d\n", size);
+  //fprintf(stderr, "iso size: %d\n", pktsize);
+  fullpkts = size / pktsize;
+  //fprintf(stderr, "Number of full packets: %d\n", fullpkts);
+  // Find length of partial packet.
+  partpktsize = size % pktsize;
+  //fprintf(stderr, "Size of partial packet: %d\n", partpktsize);
+  // Find total number of packets to be transfered.
+  packets = fullpkts + ((partpktsize > 0) ? 1 : 0);
+  //fprintf(stderr, "Total number of packets: %d\n", packets);
+  // Limit the number of packets transfered according to
+  // the Linux usbdevfs maximum read/write buffer size.
+  if ((packets < 1) || (packets > 128)) {
+    USB_ERROR_STR("error on packet size: %s", strerror(EINVAL));
+    return -EINVAL;
+  }
+
+  // If necessary, allocate the urb and packet
+  // descriptor structures from the heap.
+  local_urb = *iso_urb;
+  if (!local_urb) {
+    urb_size = sizeof(struct usbdevfs_urb) +
+      packets * sizeof(struct usb_iso_packet_desc);
+    local_urb = (struct usbdevfs_urb *) calloc(1, urb_size);
+    if (!local_urb) {
+      USB_ERROR_STR("error on packet size: %s", strerror(EINVAL));
+      return -ENOMEM;
+    }
+  }
+
+  // Set up each packet for the data to be transferred.
+  for (pktcount = 0; pktcount < fullpkts; pktcount++) {
+    local_urb->iso_frame_desc[pktcount].length = pktsize;
+    local_urb->iso_frame_desc[pktcount].actual_length = 0;
+    local_urb->iso_frame_desc[pktcount].status = 0;
+  }
+
+  // Set up the last packet for the partial data to be transferred.
+  if (partpktsize > 0) {
+    local_urb->iso_frame_desc[pktcount].length = partpktsize;
+    local_urb->iso_frame_desc[pktcount].actual_length = 0;
+    local_urb->iso_frame_desc[pktcount++].status = 0;
+  }
+
+  // Set up the URB structure.
+  local_urb->type = USBDEVFS_URB_TYPE_ISO;
+  //fprintf(stderr, "type: %d\n", local_urb->type);
+  local_urb->endpoint = ep;
+  //fprintf(stderr, "endpoint: 0x%x\n", local_urb->endpoint);
+  local_urb->status = 0;
+  local_urb->flags = USBDEVFS_URB_ISO_ASAP; // Additional flags here?
+  //fprintf(stderr, "flags: %d\n", local_urb->flags);
+  local_urb->buffer = bytes;
+  //fprintf(stderr, "buffer: 0x%x\n", local_urb->buffer);
+  local_urb->buffer_length = size;
+  //fprintf(stderr, "buffer_length: %d\n", local_urb->buffer_length);
+  local_urb->actual_length = 0;
+  local_urb->start_frame = 0;
+  //fprintf(stderr, "start_frame: %d\n", local_urb->start_frame);
+  local_urb->number_of_packets = pktcount;
+  //fprintf(stderr, "number_of_packets: %d\n", local_urb->number_of_packets);
+  local_urb->error_count = 0;
+  local_urb->signr = 0;
+  //fprintf(stderr, "signr: %d\n", local_urb->signr);
+  local_urb->usercontext = (void *) 0;
+  *iso_urb = local_urb;
+  return 0;
+}
+
+
+int usb_urb_submit(usb_dev_handle *dev,     // Open usb device handle.
+		   struct usbdevfs_urb *iso_urb,        // Pointer to URB.
+		   struct timeval *tv_submit) { // Time structure pointer.
+  int ret;
+
+  iso_urb->usercontext = dev;
+  // Get actual time, of the URB submission.
+  if(tv_submit)
+    gettimeofday(tv_submit, NULL);
+  // Submit the URB through an IOCTL call.
+  ret = ioctl(dev->fd, USBDEVFS_SUBMITURB, iso_urb);
+  //fprintf(stderr, "start_frame now: %d\n", iso_urb->start_frame);
+  //fprintf(stderr, "submit ioctl return value: %d\n", ret);
+  if (ret < 0) {
+    //fprintf(stderr, "error submitting URB: %s\n", strerror(errno));
+    USB_ERROR_STR("error submitting URB: %s", strerror(errno));
+    return -errno;
+  }
+  return ret;
+}
+
+
+int usb_urb_reap(usb_dev_handle *dev,     // Open usb device handle.
+		 struct usbdevfs_urb *iso_urb,        // Pointer to URB.
+		 int timeout) {           // Attempt timeout (usec).
+  struct timeval tv_ref, tv_msec, tv;
+  void *context;
+  int waiting, ret;
+  struct pollfd ufd[1];
+
+  // Get actual time, and add the timeout value. The result is the absolute
+  // time where we have to quit waiting for an isochronous message.
+  ufd[0].fd = dev->fd;
+  ufd[0].events = POLLIN | POLLOUT;
+  ufd[0].revents = 0;
+  ret = poll(ufd, 1, timeout);
+  if(ret <= 0)
+    return -ETIMEDOUT;
+
+  //fprintf(stderr, "preparing to reap\n");
+  ret = ioctl(dev->fd, USBDEVFS_REAPURB, &context);
+
+  /*
+   * If there was an error, that wasn"t EAGAIN (no completion), then
+   * something happened during the reaping and we should return that
+   * error now
+   */
+  //fprintf(stderr, "reap ioctl return value: %d\n", ret);
+  if (ret < 0) {
+    USB_ERROR_STR("error reaping interrupt URB: %s",
+		  strerror(errno));
+    return -errno;
+  }
+
+  //fprintf(stderr, "actual_length: %d\n", iso_urb->actual_length);
+  //fprintf(stderr, "URB status: %d\n", iso_urb->status);
+  //fprintf(stderr, "error count: %d\n", iso_urb->error_count);
+
+  //fprintf(stderr, "waiting done\n");
+  if(iso_urb != context) {
+    fprintf(stderr, "Expected urb: %p but got %p\n", iso_urb, context);
+    return -1;
+  }
+  //fprintf(stderr, "Total bytes: %d\n", bytesdone);
+  return iso_urb->actual_length;
+}
+
+int usb_urb_cancel(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb)
+{
+  return ioctl(dev->fd, USBDEVFS_DISCARDURB, iso_urb);
+}
Index: libs/libmythtv/r5000/libusb_augment.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/libusb_augment.h	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,23 @@
+// libusb_augment.h
+// $Revision$
+// $Date$
+
+#ifdef LIBUSB_AUGMENT
+// Taken from libusb file linux.h to provide the URB structure definitions.
+struct usb_iso_packet_desc {
+  unsigned int length;
+  unsigned int actual_length;
+  unsigned int status;
+};
+#endif
+
+int usbdevfs_urb_signal_completion(void (*cb)( struct usbdevfs_urb *));
+struct usbdevfs_urb *usb_bulk_setup(struct usbdevfs_urb *iso_urb, unsigned char ep,
+		   char *bytes, int size);
+int usb_isochronous_setup(struct usbdevfs_urb **iso_urb, unsigned char ep,
+			  int pktsize, char *bytes, int size);
+int usb_urb_submit(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb,
+		   struct timeval *tv_rsubmit);
+int usb_urb_reap(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb,
+		 int timeout_usec);
+int usb_urb_cancel(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb);
Index: libs/libmythtv/r5000/r5000.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5000.c	2008-02-22 15:36:58.000000000 -0800
@@ -0,0 +1,599 @@
+//#define R5K_DEBUG
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+       #include <sys/time.h>
+       #include <time.h>
+
+
+#include <usb.h>
+#include <linux/usbdevice_fs.h>
+#include "libusb_augment.h"
+#include "r5000buttons.h"
+
+#define MAX_URBS_IN_FLIGHT 128
+#define R5K_URB_BUFFER_SIZE (1 << 14)
+#define R5K_MAX_PIDS 10
+
+typedef struct {
+  usb_dev_handle *handle;
+  struct usbdevfs_urb *urbs;
+  unsigned char *buffer;
+  unsigned char leftover[188];
+  unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data);
+  void *cb_data;
+  int nexturb;
+  int streaming;
+  int offset;
+  int realtime;
+  int bytes_read;
+#ifdef R5K_DEBUG
+  int fd;
+#endif
+  unsigned char pmt_pkt[188];
+  unsigned char num_pmt_entries;
+  unsigned char pmt_state;
+  unsigned char pmt_next_cc;
+  struct {
+    int pid;
+    unsigned char id;
+  } pmt[R5K_MAX_PIDS];
+} r5kdev_t;
+
+static r5kdev_t *glbl_r5kdev;
+static int r5000_usb_init = 0;
+static unsigned char r5000_pat_pkt[188] = {
+0x47, 0x40, 0x00, 0x13, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x06, 0xc5, 0x00, 0x00, 0x00, 0x01, 0xe0,
+0x21, 0x19, 0x3a, 0x82, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+enum {
+  R5K_PMT_START = 0x01,
+  R5K_PMT_READY = 0x02
+};
+static int r5000_pmt_state = 0;
+static unsigned char r5000_pmt[188];
+static int r5000_pmt_count = 0;
+static unsigned char r5000_pmt_partial[188*20];
+static int r5000_pmt_partial_count = 0;
+static int r5000_pmt_cc;
+static void r5000_process_urb(struct usbdevfs_urb *urb);
+
+int r5000_create_urbs(r5kdev_t *r5kdev)
+{
+  int i;
+  r5kdev->urbs = (struct usbdevfs_urb *)malloc(sizeof(struct usbdevfs_urb) * MAX_URBS_IN_FLIGHT);
+  r5kdev->buffer = malloc(R5K_URB_BUFFER_SIZE * MAX_URBS_IN_FLIGHT);
+  for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) {
+    usb_bulk_setup(&r5kdev->urbs[i], 0x82, r5kdev->buffer + (R5K_URB_BUFFER_SIZE*i), R5K_URB_BUFFER_SIZE);
+  }
+  r5kdev->nexturb = 0;
+  return 0;
+}
+
+int r5000_free_urbs(r5kdev_t *r5kdev)
+{
+  free(r5kdev->urbs);
+  free(r5kdev->buffer);
+  return 0;
+}
+
+usb_dev_handle *r5000_locate_device(
+    unsigned short vendor_id, unsigned short product_id)
+{
+  struct usb_bus *bus;
+  struct usb_device *dev;
+  usb_dev_handle *device_handle = 0;
+  usb_find_busses();
+  usb_find_devices();
+
+   for (bus = usb_get_busses(); bus; bus = bus->next)
+  {
+    for (dev = bus->devices; dev; dev = dev->next)
+    {
+      if (dev->descriptor.idVendor == vendor_id &&
+          dev->descriptor.idProduct == product_id)
+      {
+        device_handle = usb_open(dev);
+        printf("XSV Device Found @ Address %s \n", dev->filename);
+        printf("XSV Vendor ID 0x0%x\n",dev->descriptor.idVendor);
+        printf("XSV Product ID 0x0%x\n",dev->descriptor.idProduct);
+      }
+    }
+  }
+
+  if (device_handle==0) return (0);
+  int open_status = usb_set_configuration(device_handle,1);
+  printf("conf_stat=%d\n",open_status);
+
+  open_status = usb_claim_interface(device_handle,0);
+  printf("claim_stat=%d\n",open_status);
+
+  open_status = usb_set_altinterface(device_handle,0);
+  printf("alt_stat=%d\n",open_status);
+  return (device_handle);
+}
+
+int r5000_start_stream(r5kdev_t *r5kdev)
+{
+  unsigned char data[0x80];
+  int bytes;
+  int i;
+  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle;
+
+  if(! r5kdev->urbs)
+    r5000_create_urbs(r5kdev);
+/*
+  data[0] = 0x20;
+  usb_bulk_write(handle, 1, data, 1, 5000);
+
+  bytes = usb_bulk_read(handle, 129, data, 4, 5000);
+  bytes = usb_bulk_read(handle, 129, data, 128, 5000);
+*/
+  data[0] = 0x30;
+  usb_bulk_write(handle, 1, data, 1, 5000);
+  bytes = usb_bulk_read(handle, 129, data, 2, 5000);
+
+  data[0] = 0x50;
+  usb_bulk_write(handle, 1, data, 1, 5000);
+
+  for(i=0; i < MAX_URBS_IN_FLIGHT; i++) {
+    usb_urb_submit(handle, &r5kdev->urbs[i], NULL);
+  }
+  r5kdev->nexturb = 0;
+  r5kdev->streaming = 1;
+  r5kdev->offset = 0;
+  return 1;
+}
+
+int r5000_stop_stream(r5kdev_t *r5kdev)
+{
+  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle;
+  struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs;
+  int i;
+
+  if(r5kdev->streaming) {
+    for(i=0; i < MAX_URBS_IN_FLIGHT; i++)
+      usb_urb_cancel(handle, &urbs[i]);
+    r5kdev->streaming = 0;
+  }
+  return 0;
+}
+
+r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, int realtime)
+{
+  r5kdev_t *r5kdev;
+  struct usb_dev_handle *handle;
+  if(! r5000_usb_init) {
+    usb_init();
+    r5000_usb_init = 1;
+  }
+  handle = r5000_locate_device(0x0547, 0x1002);
+  if(! handle)
+    return NULL;
+  if(realtime)
+    usbdevfs_urb_signal_completion(r5000_process_urb);
+  r5kdev = (r5kdev_t *)calloc(1, sizeof(r5kdev_t));
+  r5kdev->handle = handle;
+  r5kdev->urbs = NULL;
+  r5kdev->cb = cb;
+  r5kdev->cb_data = cb_data;
+  //r5kdev->realtime = realtime;
+#ifdef R5K_DEBUG
+   r5kdev->fd = open("r5kdebug.raw", O_WRONLY | O_TRUNC | O_CREAT, 0666);
+#endif
+  glbl_r5kdev = r5kdev;
+  return r5kdev;
+}
+
+int r5000_close(r5kdev_t *r5kdev)
+{
+  if(! r5kdev)
+    return 0;
+  if(r5kdev->urbs) {
+    if(r5kdev->streaming)
+      r5000_stop_stream(r5kdev);
+    r5000_free_urbs(r5kdev);
+  }
+#ifdef R5K_DEBUG
+    if(r5kdev->fd >= 0)
+      close(r5kdev->fd);
+#endif
+  usb_close(r5kdev->handle);
+  free(r5kdev);
+  return 0;
+}
+#if 0
+void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf)
+{
+  int pid = ((buf[1] << 8) | buf[2]) & 0x1fff;
+  if(pid == 0x00 && r5000_pmt_state & R5K_PMT_READY) {
+    int i;
+    for(i = 0; i < r5000_pmt_count; i++) {
+      unsigned char *ptr = r5000_pmt + 188*i;
+      r5000_pmt_cc = (r5000_pmt_cc +1) &0xf;
+      ptr[3] = (ptr[3] & 0xf0) | r5000_pmt_cc;
+      r5kdev->cb(ptr, 188, r5kdev->cb_data);
+    }
+  } else if(pid == 0x21) {
+    r5000_pmt_cc = buf[3] & 0xf;
+    if(buf[1] & 0x40 && buf[4] == 0x00 && buf[5] == 0x02) {
+      if(r5000_pmt_state & R5K_PMT_START) {
+        memcpy(r5000_pmt, r5000_pmt_partial, 188 * r5000_pmt_partial_count);
+        r5000_pmt_count = r5000_pmt_partial_count;
+        r5000_pmt_state |= R5K_PMT_READY;
+      }
+      memcpy(r5000_pmt_partial, buf, 188);
+      r5000_pmt_partial_count = 1;
+      r5000_pmt_state |= R5K_PMT_START;
+    } else if(r5000_pmt_state & R5K_PMT_START) {
+      memcpy(r5000_pmt_partial + 188*r5000_pmt_partial_count, buf, 188);
+      r5000_pmt_partial_count++;
+    }
+  }
+}
+#else
+//taken and adapted from libdtv, (c) Rolf Hakenes
+// CRC32 lookup table for polynomial 0x04c11db7
+static unsigned int crc_table[256] = {
+   0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+   0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+   0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+   0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+   0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+   0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+   0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+   0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+   0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+   0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+   0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+   0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+   0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+   0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+   0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+   0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+   0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+   0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+   0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+   0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+   0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+   0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+   0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+   0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+   0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+   0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+   0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+   0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+   0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+   0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+   0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+   0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+   0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+   0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+   0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+   0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+   0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+   0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+   0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+   0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+   0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+   0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+   0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
+
+void r5000_calc_crc(unsigned char *out, const unsigned char *d, int len)
+{
+   register int i;
+   unsigned int crc = 0xFFFFFFFF;
+   const unsigned char *u=(unsigned char*)d; // Saves '& 0xff'
+
+   for (i=0; i<len; i++)
+      crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)];
+
+   *out++ = (crc >> 24) & 0xff;
+   *out++ = (crc >> 16) & 0xff;
+   *out++ = (crc >> 8) & 0xff;
+   *out++ = (crc >> 0) & 0xff;
+}
+
+#define IS_VIDEO(x) ((x) == 0x02 || (x) == 0x1b)
+void r5000_send_pmt(r5kdev_t *r5kdev)
+{
+  if(r5kdev->pmt_pkt[0] != 0x47) {
+    int len;
+    int i;
+    unsigned char *ptr;
+    unsigned char ts[188] = {
+    0x47, 0x40, 0x21, 0x10,
+    0x00, 0x02,
+    0xb0, 0x00,  //length
+    0x00, 0x01,
+    0xc3, 0x00, 0x00,
+    0xf0, 0x00,  //PCR_PID
+    0xf0, 0x00}; //Program Info Length
+    ts[3] = 0x10 | r5kdev->pmt_next_cc;
+    printf("Building PMT\n");
+    ptr = ts + 17;
+    for(i = 0; i < r5kdev->num_pmt_entries; i++) {
+      *ptr++ = r5kdev->pmt[i].id;
+      *ptr++ = 0xe0 | (r5kdev->pmt[i].pid>>8);
+      *ptr++ = r5kdev->pmt[i].pid & 0xff;
+      *ptr++ = 0xf0;
+      if(IS_VIDEO(r5kdev->pmt[i].id)) {
+        *ptr++ = 0x00;
+	ts[13] = 0xe0 | (r5kdev->pmt[i].pid >> 8);
+	ts[14] = r5kdev->pmt[i].pid & 0xff;
+      } else {
+        *ptr++ = 0x06;
+        *ptr++ = 0x0a;
+        *ptr++ = 0x04;
+        *ptr++ = 0x65;
+        *ptr++ = 0x6e;
+        *ptr++ = 0x67;
+        *ptr++ = 0x00;
+      }
+    }
+    ts[7] = (ptr - ts) - 8/*header*/ + 4/*CRC*/;
+    r5000_calc_crc(ptr, ts + 5, (ptr - ts) - 5);
+    memset(ptr+4, 0xff, 188 - (ptr - ts - 4));
+    memcpy(r5kdev->pmt_pkt, ts, 188);
+  }
+  r5kdev->pmt_pkt[3] = 0x10 | r5kdev->pmt_next_cc;
+  r5kdev->pmt_next_cc = (r5kdev->pmt_next_cc + 1) & 0x0f;
+  r5kdev->cb(r5kdev->pmt_pkt, 188, r5kdev->cb_data);
+}
+
+void r5000_add_pmt(r5kdev_t *r5kdev, int pid, int table_id)
+{
+  int i;
+  int is_video = IS_VIDEO(table_id);
+
+  for(i = 0; i < r5kdev->num_pmt_entries; i++) {
+    if(r5kdev->pmt[i].pid == pid) {
+      if(r5kdev->pmt[i].id == table_id)
+        return;
+      //different table_id for existing pid.  Reset
+      r5kdev->num_pmt_entries = 0;
+      r5kdev->pmt_state = 0;
+      r5kdev->pmt_pkt[0] = 0;
+      break;
+    }
+    if(is_video) {
+      if(IS_VIDEO(r5kdev->pmt[i].id)) {
+        //a video entry already exists.  Reset
+        r5kdev->num_pmt_entries = 0;
+        r5kdev->pmt_state = 0;
+        r5kdev->pmt_pkt[0] = 0;
+	break;
+      }
+    }
+  }
+  //Didn't find this PID, add it
+  if(i == R5K_MAX_PIDS)
+    return;
+  printf("Adding %04x: %02x @ %08x\n", pid, table_id, r5kdev->bytes_read);
+  r5kdev->pmt[r5kdev->num_pmt_entries].pid = pid;
+  r5kdev->pmt[r5kdev->num_pmt_entries].id  = table_id;
+  r5kdev->num_pmt_entries++;
+  r5kdev->pmt_state |= is_video ? 0x01 : 0x02;
+}
+
+void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf)
+{
+  int stream_id, pid, afc, af_size = 0;
+  pid = ((buf[1] << 8) | buf[2]) & 0x1fff;
+  if(pid == 0x1fff)
+    return;
+  if(pid == 0) {
+    r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
+    if(r5kdev->pmt_state == 0x03)
+      r5000_send_pmt(r5kdev);
+  } else {
+    if(pid != 0x21)
+      r5kdev->cb(buf, 188, r5kdev->cb_data);
+    //Only interested in PES packets starting in this TS packet
+    if (!buf[1] & 0x40)
+      return;
+    afc = (buf[3]>>4) & 0x03;
+    if(afc == 0x2)
+      return;
+    if(afc == 0x3)
+      af_size = buf[4]+1;
+    if(buf[4+af_size] != 0x00 || buf[5+af_size] != 0x00 || buf[6+af_size] != 0x01)
+      return;
+    //We have a PES packet
+    stream_id = buf[7+af_size];
+    if((stream_id & 0xf0) == 0xe0) {
+      //Video stream (we need the adaptation field)
+      if(afc != 0x03)
+        return;
+      if(0) {
+        int i;
+        for(i = 0; i < af_size+8; i++) {
+	  printf("%02x ", buf[i]);
+	  if((i %16) == 15)
+            printf("\n");
+        }
+        printf("\n");
+      }
+      if(buf[5] & 0x02) {
+        // Has private data, this is MPEG4
+        r5000_add_pmt(r5kdev, pid, 0x1b);
+      } else if(buf[5] & 0x10) {
+        // Has PCR and no private data, this is MPEG2
+        r5000_add_pmt(r5kdev, pid, 0x02);
+      }
+    } else if((stream_id & 0xf0) == 0xc0) {
+      //Audio stream
+      r5000_add_pmt(r5kdev, pid, 0x04);
+    } else if(stream_id  == 0xbd) {
+      //Audio stream
+      r5000_add_pmt(r5kdev, pid, 0x81);
+    }
+  }
+}
+#endif
+void r5000_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len)
+{
+  int pos;
+  int sync = 1;
+  if(! r5kdev->streaming)
+    return;
+  if(len <= 0)
+    return;
+
+  pos = r5kdev->offset;
+#ifdef R5K_DEBUG
+  if(r5kdev->fd >= 0)
+    write(r5kdev->fd, buf, len);
+#endif
+  while(pos < len) {
+      if(buf[pos] != 0x47 || (pos <len-1 && buf[pos+1] == 0xff))
+        goto nosync;
+      // If we get here, buf[pos] == 0x47
+      if(r5kdev->offset) {
+        //previous data exists and is part of a good packet
+        memcpy(r5kdev->leftover+188-r5kdev->offset, buf, r5kdev->offset);
+	r5000_force_pmt(r5kdev, r5kdev->leftover);
+        r5kdev->offset = 0;
+      }
+      if(pos+188 < len) {
+        //at least one full packet is available
+        if(buf[pos+188] != 0x47)
+          goto nosync;
+      } else {
+        //Out of data, but the partial packet may be ok.
+        memcpy(r5kdev->leftover, buf+pos, len-pos);
+        r5kdev->offset = 188-(len-pos);
+        break;
+      }
+      //If we get here, we have a good packet
+      r5000_force_pmt(r5kdev, buf+pos);
+      if(! sync)
+        printf("(%d) Found sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos);
+      sync = 1;
+      pos+=188;
+      continue;
+  nosync:
+      r5kdev->offset=0;
+      if(sync)
+        printf("(%d)Lost sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos);
+      sync = 0;
+      pos++;
+  }
+  r5kdev->bytes_read += len;
+}
+
+int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec)
+{
+  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle;
+  struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs;
+  int len;
+  unsigned char *buf;
+  struct timeval tv1, tv2;
+  if(! r5kdev->streaming)
+    return -1;
+  gettimeofday(&tv1, NULL);
+  len = usb_urb_reap(handle, &urbs[r5kdev->nexturb], timeout_usec);
+  gettimeofday(&tv2, NULL);
+  //printf("%u.%06u (%u.%06u) Read %d bytes\n", (unsigned int)tv1.tv_sec, (unsigned int)tv1.tv_usec, (unsigned int)tv2.tv_sec, (unsigned int)tv2.tv_usec, len);
+  if(len <= 0) {
+    if(len != -ETIMEDOUT)
+      printf("(%d) Reap failed at %08x: %s\n", r5kdev->nexturb, r5kdev->bytes_read, strerror(errno));
+    return len;
+  }
+  buf = r5kdev->buffer + (R5K_URB_BUFFER_SIZE*r5kdev->nexturb);
+  r5000_process_block(r5kdev, buf, len);
+  usb_urb_submit(handle, &urbs[r5kdev->nexturb], NULL);
+  r5kdev->nexturb = (r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT;
+  return 0;
+}
+
+static void r5000_process_urb(struct usbdevfs_urb *urb)
+{
+//  struct timeval tv;
+//  gettimeofday(&tv, NULL);
+//  printf("Callback at %d.%06d: %d/%d\n", tv.tv_sec, tv.tv_usec, urb->buffer_length, urb->actual_length);
+  if(urb != &glbl_r5kdev->urbs[glbl_r5kdev->nexturb]) {
+    int i;
+    for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) {
+      if(urb == &glbl_r5kdev->urbs[i])
+      break;
+    }
+    printf("Discontinuity: Expected %d but got %d!\n", glbl_r5kdev->nexturb, i);
+  }
+  r5000_process_block(glbl_r5kdev, urb->buffer, urb->actual_length);
+  usb_urb_submit(glbl_r5kdev->handle, urb, NULL);
+  glbl_r5kdev->nexturb = (glbl_r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT;
+}
+
+int r5000_read_status(r5kdev_t *r5kdev, unsigned char *buf)
+{
+  return usb_bulk_read(r5kdev->handle, 129, buf, 128, 5000);
+}
+
+int r5000_get_power_state(r5kdev_t *r5kdev)
+{
+  unsigned char data1[1]  = { 0x30 };
+  unsigned char data2[0x80];
+  while(1) {
+    r5000_read_status(r5kdev, data2);
+    usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000);
+    usleep(100000);
+    if(usb_bulk_read(r5kdev->handle, 1, data2, 2, 5000) == 2 &&
+       data2[0] == 0x0a || (data2[1] & 0x4e) == 0x4c)
+      return !!(data2[1] == 0x4d);
+    usleep(100000);
+  }
+}
+
+int r5000_toggle_on_off(r5kdev_t *r5kdev)
+{
+  unsigned char data1[1]  = { 0x30 };
+  unsigned char data3[0x80], on_off;
+  int len;
+  on_off = r5000_get_power_state(r5kdev);
+  //printf("Start state: %s\n", on_off ? "On" : "Off");
+  usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000);
+  usleep(100000);
+  usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_POWER], 0x40, 5000);
+  usleep(100000);
+  len = usb_bulk_read(r5kdev->handle, 1, data3, 2, 5000);
+  usleep(100000);
+  while(r5000_get_power_state(r5kdev) == on_off)
+    usleep(100000);
+  //printf("End state: %s\n", !on_off ? "On" : "Off");
+  return !on_off;
+}
+
+void r5000_change_channel(r5kdev_t *r5kdev, int chan)
+{
+  int pos = 1000000, digit;
+  unsigned char data2[0x80];
+  r5000_read_status(r5kdev, data2);
+  usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_CLEAR], 0x40, 5000);
+  usleep(R5000_BUTTON_DELAY);
+  while(pos != 0 && (chan/pos) == 0)
+    pos /= 10;
+  if(pos == 0)
+    pos = 1;
+  while(pos != 0) {
+    digit = chan / pos;
+    usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[digit], 0x40, 5000);
+    chan -= digit*pos;
+    pos/= 10;
+    usleep(R5000_BUTTON_DELAY);
+  }
+  usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_ENTER], 0x40, 5000);
+}
Index: libs/libmythtv/r5000/r5000.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5000.h	2008-02-22 15:34:57.000000000 -0800
@@ -0,0 +1,14 @@
+#ifndef R5000_H
+#define R5000_H
+
+#define r5kdev_t void
+
+extern r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, int realtime);
+extern int r5000_close(r5kdev_t *r5kdev);
+extern int r5000_start_stream(r5kdev_t *r5kdev);
+extern int r5000_stop_stream(r5kdev_t *r5kdev);
+extern int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec);
+extern int r5000_get_power_state(r5kdev_t *r5kdev);
+extern int r5000_toggle_on_off(r5kdev_t *r5kdev);
+extern void r5000_change_channel(r5kdev_t *r5kdev, int chan);
+#endif //R5000_H
Index: libs/libmythtv/r5000/r5000buttons.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5000buttons.h	2008-02-22 15:37:40.000000000 -0800
@@ -0,0 +1,113 @@
+///This has only been verified for a VIP211.  Quite possibly different buttons are needed for different receivers.
+//
+#define R5000_BUTTON_DELAY 400000
+enum {
+  R5K_BUTTON_0 = 0,
+  R5K_BUTTON_1,
+  R5K_BUTTON_2,
+  R5K_BUTTON_3,
+  R5K_BUTTON_4,
+  R5K_BUTTON_5,
+  R5K_BUTTON_6,
+  R5K_BUTTON_7,
+  R5K_BUTTON_8,
+  R5K_BUTTON_9,
+  R5K_BUTTON_CLEAR,
+  R5K_BUTTON_ENTER,
+  R5K_BUTTON_POWER,
+  R5K_BUTTON_MAX
+};
+const unsigned char r5000_button_cmd[R5K_BUTTON_MAX][0x40] =
+{
+//button 0:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 1:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 2:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 3:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 4:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 5:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 6:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 7:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 8:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+ 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//button 9:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//Clear:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//Enter:
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//Power
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+}
+};

