Index: configure
===================================================================
--- configure.orig	2009-01-01 09:29:38.000000000 -0800
+++ configure	2009-01-01 09:29:43.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]"
@@ -891,6 +892,7 @@
     hdhomerun
     iptv
     ivtv
+    r5000
     joystick_menu
     libfftw3
     lirc
@@ -1046,6 +1048,7 @@
 dbox2_deps="backend"
 dvb_deps="backend"
 firewire_deps="backend"
+r5000_deps="backend"
 iptv_deps="backend"
 ivtv_deps="backend v4l"
 hdhomerun_deps="backend"
@@ -1179,6 +1182,7 @@
 hdhomerun="yes"
 iptv="yes"
 ivtv="yes"
+r5000="yes"
 joystick_menu="default"
 lamemp3="yes"
 lirc="yes"
@@ -2717,6 +2721,8 @@
 enabled libfftw3 && has_library libfftw3_threads && has_header fftw3.h ||
     disable libfftw3
 
+enabled r5000 && has_library libusb && check_header usb.h || disable r5000
+
 enabled x11 && has_library libX11 || disable x11
 enabled xrandr && has_header X11/extensions/Xrandr.h || disable xrandr
 enabled xv && has_library libXv || disable xv
@@ -2998,6 +3004,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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/cardutil.h	2009-01-01 09:29:43.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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/libmythtv.pro	2009-01-01 09:29:43.000000000 -0800
@@ -496,6 +496,25 @@
         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
+	HEADERS += r5000/r5000_internal.h   r5000/r5000init.h
+
+        SOURCES += r5000channel.cpp         r5000recorder.cpp
+        SOURCES += r5000signalmonitor.cpp   r5000device.cpp
+	SOURCES += r5000/r5000.c            r5000/libusb_augment.c
+	SOURCES += r5000/r5k_vip.c          r5000/r5k_pes.c
+	SOURCES += r5000/r5k_sat.c          r5000/r5k_misc.c
+	SOURCES += r5000/r5k_vip_buttons.c  r5000/r5k_directv_buttons.c
+	SOURCES += r5000/r5k_dish6000_buttons.c
+
+	LIBS += -lusb
+        DEFINES += USING_R5000
+    }
+
     DEFINES += USING_BACKEND
 }
 
Index: libs/libmythtv/signalmonitor.h
===================================================================
--- libs/libmythtv/signalmonitor.h.orig	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/signalmonitor.h	2009-01-01 09:29:43.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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/signalmonitor.cpp	2009-01-01 09:29:43.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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/cardutil.cpp	2009-01-01 09:29:43.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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/videosource.cpp	2009-01-01 09:29:43.000000000 -0800
@@ -36,6 +36,7 @@
 #include "frequencies.h"
 #include "diseqcsettings.h"
 #include "firewiredevice.h"
+#include "r5000device.h"
 #include "compat.h"
 
 
@@ -1299,6 +1300,83 @@
     }
 };
 
+class R5000SendPowerBeforeChannel : public CheckBoxSetting, public CaptureCardDBStorage
+{
+  public:
+    R5000SendPowerBeforeChannel(const CaptureCard &parent) :
+        CheckBoxSetting(this),
+        CaptureCardDBStorage(this, parent, "dvb_on_demand")
+    {
+        setValue(false);
+        setLabel(QObject::tr("Turn on before Channel Change"));
+        setHelpText(QObject::tr(
+                        "On some STBs klike the ViP211, the power on/off "
+                        "detection isn't reliable if you let the box go into "
+                        "standby.  This forces a 'power-on' command before "
+                        "changing channels.  This will very likely do the "
+                        "wrong thing for non ViP boxes."));
+
+    };
+};
+
+class R5000Serial : public ComboBoxSetting, public CaptureCardDBStorage
+{
+  public:
+    R5000Serial(const CaptureCard &parent) :
+        ComboBoxSetting(this),
+        CaptureCardDBStorage(this, parent, "videodevice")
+    {
+        setLabel(QObject::tr("Serial #"));
+#ifdef USING_R5000
+        QStringList serials = R5000Device::GetSTBList();
+        for (uint i = 0; i < serials.size(); i++)
+        {
+            addSelection(serials[i]);
+        }
+#endif // USING_R5000
+    }
+};
+
+class R5000Model : public ComboBoxSetting, public CaptureCardDBStorage
+{
+  public:
+    R5000Model(const CaptureCard  &parent) :
+      ComboBoxSetting(this),
+      CaptureCardDBStorage(this, parent, "firewire_model")
+    {
+        setLabel(QObject::tr("R5000 STB type"));
+        addSelection("VIP211");
+        addSelection("VIP411");
+        addSelection("VIP622");
+        addSelection("VIP722");
+        addSelection("BEV9242");
+        addSelection("DISH6000");
+        addSelection("DIRECTV");
+        addSelection("STARCHOICE/DSR");
+        addSelection("HDD-200");
+        QString help = QObject::tr(
+            "Choose the type of R5000 enabled STB you are using.");
+        setHelpText(help);
+    }
+};
+class R5000ConfigurationGroup : public VerticalConfigurationGroup
+{
+  public:
+    R5000ConfigurationGroup(CaptureCard& a_parent):
+       VerticalConfigurationGroup(false, true, false, false),
+       parent(a_parent)
+    {
+        setUseLabel(false);
+        addChild(new R5000SendPowerBeforeChannel(parent));
+        addChild(new R5000Serial(parent));
+        addChild(new R5000Model(parent));
+        addChild(new SingleCardInput(parent));
+    };
+
+  private:
+    CaptureCard &parent;
+};
+
 class IPTVHost : public LineEditSetting, public CaptureCardDBStorage
 {
   public:
@@ -1483,6 +1561,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) 
@@ -1670,6 +1752,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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/tv_rec.cpp	2009-01-01 09:29:43.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.model, dvbOpt.dvb_on_demand);
+        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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/transporteditor.cpp	2009-01-01 09:29:43.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	2009-01-01 09:29:38.000000000 -0800
+++ libs/libmythtv/tv_rec.h	2009-01-01 09:29:43.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	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,201 @@
+/**
+ *  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 QString &_r5ktype, bool pocc) :
+    DTVChannel(parent),
+    videodevice(_videodevice),
+    power_on_channel_change(pocc),
+    device(NULL),
+    current_channel(""),
+    current_mpeg_prog(0),
+    isopen(false)
+{
+    int type = R5000Device::GetDeviceType(_r5ktype);
+    device = new R5000Device(type, videodevice);
+
+    InitializeInputs();
+}
+
+bool R5000Channel::SetChannelByString(const QString &channum)
+{
+    QString loc = LOC + QString("SetChannelByString(%1)").arg(channum);
+    bool ok = false;
+    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;
+    }
+
+    if (!(*it)->externalChanger.isEmpty())
+    {
+        ok = ChangeExternalChannel(freqid);
+        // -1 resets any state without executing a channel change
+        device->SetChannel(fw_opts.model, 0, mpeg_prog_num);
+        SetSIStandard("mpeg");
+        SetDTVInfo(0,0,0,0,1);
+    }
+    else
+    {
+        ok = isopen && SetChannelByNumber(freqid, mpeg_prog_num);
+    }
+
+    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, current_mpeg_prog);
+
+    return false;
+}
+
+bool R5000Channel::SetChannelByNumber(const QString &channel, int mpeg_prog)
+{
+    VERBOSE(VB_CHANNEL, QString("SetChannelByNumber(%1)").arg(channel));
+    current_channel = channel;
+    current_mpeg_prog = mpeg_prog;
+
+    if (!power_on_channel_change && 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...
+    }
+
+    QString tmpchan = (power_on_channel_change ? "P" : "") + channel;
+    if (!device->SetChannel(fw_opts.model, tmpchan, mpeg_prog))
+        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	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,427 @@
+/**
+ *  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 int r5k_init = 0;
+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;
+}
+
+void r5000_msg(char * msg)
+{
+    VERBOSE(VB_IMPORTANT, "R5kLib: "<<msg);
+}
+
+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(int type, QString serial) :
+    m_type(type),
+    m_serial(serial),
+    m_last_channel(""),      m_last_crc(0),
+    m_buffer_cleared(true), m_open_port_cnt(0),
+    m_lock(false),          m_priv(new R5kPriv())
+{
+    QMutexLocker locker(&s_static_lock);
+    usbdev = NULL;
+    if(! r5k_init)
+      r5k_init = r5000_init(r5000_msg);
+}
+
+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));
+    r5000_power_on_off(usbdev, on);
+    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,
+                                const QString &channel, uint mpeg_prog)
+{
+    VERBOSE(VB_CHANNEL, QString("SetChannel(model %1, chan %2 mpeg_prog %3)")
+            .arg(panel_model).arg(channel).arg(mpeg_prog));
+
+    QMutexLocker locker(&m_lock);
+    VERBOSE(VB_CHANNEL, "SetChannel() -- locked");
+    if(! r5000_change_channel(usbdev, channel.ascii(), mpeg_prog))
+        VERBOSE(VB_IMPORTANT, LOC + "Failed to set 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 QString &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;
+    }
+
+    if(m_serial) {
+      VERBOSE(VB_RECORD, LOC + QString("Opening R5000 device type %1 with serial#: "+ m_serial).arg(m_type));
+      usbdev = r5000_open((r5ktype_t)m_type, r5000_device_tspacket_handler, this, m_serial.ascii());
+    } else {
+      VERBOSE(VB_RECORD, LOC + "Opening R5000 device with unknown serial#");
+      usbdev = r5000_open((r5ktype_t)m_type, r5000_device_tspacket_handler, this, NULL);
+    }
+    if(! usbdev) {
+        VERBOSE(VB_IMPORTANT, LOC + "Failed to open R5000 device");
+        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");
+}
+
+QStringList R5000Device::GetSTBList(void)
+{
+    QStringList STBList;
+    int i;
+    r5kenum_t r5k_stbs;
+    if(! r5k_init) {
+        r5k_init = r5000_init(r5000_msg);
+        if(! r5k_init)
+            return STBList;
+    }
+    if (! r5000_find_stbs(&r5k_stbs))
+        VERBOSE(VB_IMPORTANT, LOC + "Locating R5000 devices failed."
+                                    "  This may be a permission problem");
+
+    for (i = 0; i < r5k_stbs.count; i++)
+        STBList.append((char *)r5k_stbs.serial[i]);
+    return STBList;
+}
+
+int R5000Device::GetDeviceType(const QString &r5ktype)
+{
+  QString type = r5ktype.upper();
+  if(type == "DIRECTV") {
+    return R5K_STB_DIRECTV;
+  } else if(type == "VIP211/VIP622/DISH411" ||
+            type == "VIP211/VIP422" ||
+            type == "VIP211" ||
+            type == "VIP411") {
+    return R5K_STB_VIP211;
+  } else if(type == "STARCHOICE/DSR") {
+    return R5K_STB_DSR;
+  } else if(type == "HDD-200") {
+    return R5K_STB_HDD;
+  } else if(type == "VIP622" ||
+            type == "VIP722" ||
+            type == "BEV9242") {
+    return R5K_STB_VIP622;
+  } else if(type == "DISH6000") {
+    return R5K_STB_DISH6000;
+  } else {
+    return R5K_STB_VIP211;
+  }
+}
Index: libs/libmythtv/r5000recorder.cpp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000recorder.cpp	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,247 @@
+/**
+ *  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)
+{
+    //_wait_for_keyframe_option = 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())
+        {
+            ProgramMapTable *pmt = GetStreamData()->PMTSingleProgram();
+            uint video_stream_type = pmt->StreamType(pmt->FindPID(lpid));
+
+            if (video_stream_type == StreamID::H264Video)
+                _buffer_packets = !FindH264Keyframes(&tspacket);
+            else if (StreamID::IsVideo(video_stream_type))
+                _buffer_packets = !FindMPEG2Keyframes(&tspacket);
+
+            if ((video_stream_type != StreamID::H264Video) || _seen_sps)
+                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	2009-01-01 09:29:43.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	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,53 @@
+/**
+ *  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 QString &_r5ktype, bool pocc);
+    ~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(const QString &channel, int mpeg_prog);
+    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;
+    bool               power_on_channel_change;
+    R5000Device        *device;
+    QString            current_channel;
+    uint               current_mpeg_prog;
+    bool               isopen;
+};
+
+#endif // _FIREWIRECHANNEL_H_
Index: libs/libmythtv/r5000device.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000device.h	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,110 @@
+/**
+ *  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 param 0
+    typedef enum
+    {
+        kAVCPowerStateOn           = 0x70,
+        kAVCPowerStateOff          = 0x60,
+        kAVCPowerStateQuery        = 0x7f,
+    } IEEE1394UnitPowerParam0;
+
+    R5000Device(int type, QString serial);
+    ~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,
+                            const QString &channel, uint mpeg_prog);
+
+    // 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);
+    static QStringList GetSTBList(void);
+    static int GetDeviceType(const QString &r5ktype);
+    void BroadcastToListeners(
+        const unsigned char *data, uint dataSize);
+
+  protected:
+
+    bool GetSubunitInfo(uint8_t table[32]);
+
+    void SetLastChannel(const QString &channel);
+    void ProcessPATPacket(const TSPacket&);
+    bool StartStreaming(void);
+    bool StopStreaming(void);
+
+    int                      m_type;
+    QString                  m_serial;
+    uint                     m_subunitid;
+    uint                     m_speed;
+    QString                  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	2009-01-01 09:29:43.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	2009-01-01 09:29:43.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	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,311 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ * 2005-10-19/lindi: downloaded from http://www.gaesi.org/~nmct/cvista/cvista/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// 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
+struct usbdevfs_urb *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 NULL;
+  }
+
+  // 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 NULL;
+  }
+
+  // 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 NULL;
+    }
+  }
+
+  // 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;
+  return local_urb;
+}
+
+
+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).
+  void *context = NULL;
+  int 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(context != NULL && 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	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,36 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ * 2005-10-19/lindi: downloaded from http://www.gaesi.org/~nmct/cvista/cvista/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+struct usbdevfs_urb *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	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,553 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#ifdef R5K_DEBUG
+char strmfile[256] = "/tmp/strm";
+int fd = -1;
+#endif
+
+#ifdef R5K_RAWUSB
+int usbfd = -1;
+#endif
+#include "r5000_internal.h"
+#include "r5000init.h"
+
+#define R5K_WARM_VID 0x0547
+#define R5K_WARM_PID 0x1002
+
+#define MAX_URBS_IN_FLIGHT 128
+
+#ifndef USE_ISOCHRONOUS
+  //BULK
+  #define R5K_URB_BUFFER_SIZE (1 << 14)
+#else
+  //ISOCHRONOUS
+  #define LIBUSB_AUGMENT
+  #define R5K_URB_BUFFER_SIZE (1 << 15)
+#endif
+#include "libusb_augment.h"
+
+static int r5000_usb_init = 0;
+static struct {
+  unsigned char serial[R5K_MAX_DEVS][8];
+  struct usb_device *dev[R5K_MAX_DEVS];
+  int count;
+} r5000_dev_map;
+
+static void (*msgcb)(char *msg);
+
+enum {
+  R5K_PMT_START = 0x01,
+  R5K_PMT_READY = 0x02
+};
+
+void r5000_print(const char *fmt, ...)
+{
+  va_list args;
+  char logmsg[1024];
+  va_start(args,fmt);
+  vsnprintf(logmsg,sizeof(logmsg),fmt,args);
+  va_end(args);
+  if(msgcb) {
+    //msgcb routine must ensure thread safeness
+    msgcb(logmsg);
+  } else {
+    fprintf(stderr, logmsg);
+  }
+}
+
+int r5000_create_urbs(r5kdev_t *r5kdev)
+{
+  int i, urbsize;
+#ifndef USE_ISOCHRONOUS
+  urbsize = sizeof(struct usbdevfs_urb);
+#else
+  urbsize = sizeof(struct usbdevfs_urb) + sizeof(struct usb_iso_packet_desc) * R5K_URB_BUFFER_SIZE / 1024;
+#endif
+
+  r5kdev->buffer = malloc(R5K_URB_BUFFER_SIZE * MAX_URBS_IN_FLIGHT);
+  r5kdev->urbs = (struct usbdevfs_urb **)malloc(sizeof(struct usbdevfs_urb *) * MAX_URBS_IN_FLIGHT);
+  r5kdev->urbblk = (void *)malloc(urbsize * MAX_URBS_IN_FLIGHT);
+  for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) {
+    r5kdev->urbs[i] = (struct usbdevfs_urb *)((unsigned long)r5kdev->urbblk + (urbsize * i));
+#ifndef USE_ISOCHRONOUS
+    usb_bulk_setup(r5kdev->urbs[i], 0x82, r5kdev->buffer + (R5K_URB_BUFFER_SIZE*i), R5K_URB_BUFFER_SIZE);
+#else
+    usb_isochronous_setup(r5kdev->urbs[i], 0x82, 1024, r5kdev->buffer + (R5K_URB_BUFFER_SIZE*i), R5K_URB_BUFFER_SIZE);
+#endif
+  }
+  r5kdev->nexturb = 0;
+  return 1;
+}
+
+int r5000_free_urbs(r5kdev_t *r5kdev)
+{
+  free(r5kdev->urbblk);
+  free(r5kdev->urbs);
+  free(r5kdev->buffer);
+  return 0;
+}
+
+usb_dev_handle *r5000_locate_device(
+    unsigned short vendor_id, unsigned short product_id, int skip)
+{
+  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 && !device_handle; bus = bus->next)
+  {
+    for (dev = bus->devices; dev && !device_handle; dev = dev->next)
+    {
+      if (dev->descriptor.idVendor == vendor_id &&
+          dev->descriptor.idProduct == product_id)
+      {
+        device_handle = usb_open(dev);
+        if(device_handle && skip) {
+          usb_close(device_handle);
+          device_handle = NULL;
+          skip--;
+        }
+      }
+    }
+  }
+
+  if (device_handle) {
+    int open_status = usb_set_configuration(device_handle,1);
+
+    open_status = usb_claim_interface(device_handle,0);
+
+    open_status = usb_set_altinterface(device_handle,0);
+  }
+  return (device_handle);
+}
+
+int r5000_dev_init(r5kdev_t *r5kdev) {
+  int i, bytes;
+  unsigned char *ptr, *serial = r5kdev->serial;
+  unsigned char datain[0x80];
+  bytes = usb_bulk_read(r5kdev->handle, 129, datain, sizeof(datain), 5000);
+  for(i = 0; i < R5K_INIT_SERIAL; i++) {
+    //PRINTHEX("Write:\n", r5kinit[i].data, r5kinit[i].wlen);
+    if(r5kinit[i].wsleep) usleep(r5kinit[i].wsleep);
+    usb_bulk_write(r5kdev->handle, 1, r5kinit[i].data, r5kinit[i].wlen, 5000);
+    if(r5kinit[i].rsleep) usleep(r5kinit[i].rsleep);
+    bytes = usb_bulk_read(r5kdev->handle, 129, datain, sizeof(datain), 5000);
+    //PRINTHEX("Read:\n", datain, bytes);
+    if(r5kinit[i].rlen > 0 && bytes != r5kinit[i].rlen) {
+      r5000_print("R5000 initialization failed at stage %d:\n\tExpected %d bytes, but got %d bytes\n", i, r5kinit[i].rlen, bytes);
+      return 0;
+    }
+  }
+
+  //last read is serial #
+  if (datain[0] != 0x08) {
+    r5000_print("R5000 initialization failed reading serial #\n");
+    return 0;
+  }
+  for(ptr = datain + 6; ptr < datain + 13; ptr++) {
+    *serial++ = ( *ptr >= '0' && *ptr <= 'z' ) ? *ptr : '*';
+  }
+  *serial = 0;
+
+  //complete initialization now
+  for(; i < R5K_INIT_MAX; i++) {
+    //PRINTHEX("Write:\n", r5kinit[i].data, r5kinit[i].wlen);
+    if(r5kinit[i].wsleep) usleep(r5kinit[i].wsleep);
+    usb_bulk_write(r5kdev->handle, 1, r5kinit[i].data, r5kinit[i].wlen, 5000);
+    if(r5kinit[i].rsleep) usleep(r5kinit[i].rsleep);
+    bytes = usb_bulk_read(r5kdev->handle, 129, datain, sizeof(datain), 5000);
+    //PRINTHEX("Read:\n", datain, bytes);
+    if(r5kinit[i].rlen > 0 && bytes != r5kinit[i].rlen) {
+      r5000_print("R5000 initialization failed at stage %d:\n\tExpected %d bytes, but got %d bytes\n", i, r5kinit[i].rlen, bytes);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+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] = 0x30;
+  usb_bulk_write(handle, 1, data, 1, 5000);
+  bytes = usb_bulk_read(handle, 129, data, 2, 5000);
+
+  //0x50 sets byte mode.  Use '0x60' to set word mode
+  data[0] = r5kdev->read_words ? 0x60: 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;
+  if(r5kdev->start_stream)
+    r5kdev->start_stream(r5kdev);
+  return 1;
+}
+
+int r5000_stop_stream(r5kdev_t *r5kdev)
+{
+  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle;
+  struct usbdevfs_urb **urbs = 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 1;
+}
+
+/* r5000_init must be called from a thread-safe context */
+int r5000_init(void (*_msgcb)(char *str))
+{
+  int bus_count, dev_count;
+  r5kdev_t r5kd;
+  int count = 0;
+
+  msgcb = _msgcb;
+
+  if(r5000_usb_init)
+    return 1;
+  usb_init();
+  bus_count = usb_find_busses();
+  dev_count = usb_find_devices();
+  if(bus_count == 0 || dev_count ==0) {
+    r5000_print("R5000 failed to locate any USB devices.  Are you sure you have permissions set properly?\n");
+    return 0;
+  }
+  while(r5000_dev_map.count < R5K_MAX_DEVS) {
+    r5kd.handle = r5000_locate_device(R5K_WARM_VID, R5K_WARM_PID, count);
+    if(! r5kd.handle)
+      break;
+    if (r5000_dev_init(&r5kd)) {
+      memcpy(r5000_dev_map.serial[r5000_dev_map.count], r5kd.serial, 8);
+      r5000_dev_map.dev[r5000_dev_map.count] = usb_device(r5kd.handle);
+      r5000_dev_map.count++;
+    }
+    count++;
+    usb_close(r5kd.handle);
+  }
+  if(! r5000_dev_map.count) {
+    r5000_print("R5000 failed to locate any R5000 devices.  Are you sure you have permissions set properly?\n");
+    return 0;
+  }
+  r5000_usb_init = 1;
+  return 1;
+}
+
+r5kdev_t *r5000_open(r5ktype_t type,
+                     unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data),
+                     void *cb_data,
+                     const char *serial)
+{
+  r5kdev_t *r5kdev, r5kd;
+  int count = 0;
+  memset(&r5kd, 0, sizeof(r5kdev_t));
+
+  if(! r5000_usb_init) {
+    r5000_print("R5000 was not initialized before r5000_open().  Please call r5000_init() first\n");
+    return NULL;
+  }
+  for(count = 0; count < r5000_dev_map.count; count++) {
+    if(! serial || memcmp(r5000_dev_map.serial[count], serial, 8) == 0) {
+      r5kd.handle = usb_open(r5000_dev_map.dev[count]);
+      if(! r5kd.handle)
+        return NULL;
+      usb_set_configuration(r5kd.handle,1);
+      usb_claim_interface(r5kd.handle,0);
+      usb_set_altinterface(r5kd.handle,0);
+      if(! r5000_dev_init(&r5kd)) {
+        usb_close(r5kd.handle);
+        return NULL;
+      }
+      break;
+    }
+  }
+  if(count == r5000_dev_map.count) {
+    //We can't get here unless a serial was specified
+    r5000_print("Could not locate R5000 device with serial '%s'\n", serial);
+    return NULL;
+  }
+#ifdef R5K_DEBUG
+  printf("Reading stream file: %s\n", strmfile);
+  fd = open(strmfile, O_RDONLY);
+#endif
+#ifdef R5K_RAWUSB
+  usbfd = open("raw.av", O_WRONLY | O_CREAT | O_TRUNC, 0666);
+#endif
+  r5kdev = (r5kdev_t *)malloc(sizeof(r5kdev_t));
+  *r5kdev = r5kd;
+  r5kdev->urbs = NULL;
+  r5kdev->cb = cb;
+  r5kdev->cb_data = cb_data;
+  r5kdev->stb_type = type;
+  switch(type) {
+    case R5K_STB_VIP211:
+    case R5K_STB_VIP622:
+      vip_init(r5kdev);
+      break;
+    case R5K_STB_DIRECTV:
+    case R5K_STB_DISH6000:
+      pes_init(r5kdev);
+      break;
+    case R5K_STB_DSR:
+    case R5K_STB_HDD:
+      sat_init(r5kdev);
+      break;
+    default:
+      r5000_print("Unknown STB type %d specified.\n", type);
+      r5kdev->stb_type = R5K_STB_VIP211;
+      vip_init(r5kdev);
+      break;
+  }
+  return r5kdev;
+}
+
+int r5000_close(r5kdev_t *r5kdev)
+{
+  if(! r5kdev)
+    return 1;
+  if(r5kdev->urbs) {
+    if(r5kdev->streaming)
+      r5000_stop_stream(r5kdev);
+    r5000_free_urbs(r5kdev);
+  }
+  usb_close(r5kdev->handle);
+#ifdef R5K_RAWUSB
+  if(usbfd >= 0) close(usbfd);
+#endif
+  switch(r5kdev->stb_type) {
+    case R5K_STB_VIP211:
+    case R5K_STB_VIP622:
+      vip_free(r5kdev);
+      break;
+    case R5K_STB_DIRECTV:
+    case R5K_STB_DISH6000:
+      pes_free(r5kdev);
+      break;
+    case R5K_STB_DSR:
+    case R5K_STB_HDD:
+      sat_free(r5kdev);
+      break;
+  }
+  free(r5kdev);
+  return 1;
+}
+
+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 = r5kdev->urbs;
+  int len;
+  unsigned char *buf;
+  if(! r5kdev->streaming)
+    return -1;
+  len = usb_urb_reap(handle, urbs[r5kdev->nexturb], timeout_usec);
+  if(len <= 0) {
+    if(len != -ETIMEDOUT)
+      r5000_print("(%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);
+#ifdef R5K_RAWUSB
+  if(usbfd >= 0) write(usbfd, buf, len);
+#endif
+#ifdef R5K_DEBUG
+  if(fd >= 0) {
+    int newlen = read(fd, buf, len);
+    if(newlen < len) {
+      r5000_print("hit end of debug file\n");
+      lseek(fd, 0, SEEK_SET);
+      read(fd, buf + newlen, len - newlen);
+    }
+  }
+#endif
+  r5kdev->process_block(r5kdev, buf, len);
+  r5kdev->bytes_read += len;
+  usb_urb_submit(handle, urbs[r5kdev->nexturb], NULL);
+  r5kdev->nexturb = (r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT;
+  return 0;
+}
+
+//use this to read a status frame.  It doesn't do anything special
+//but makes it obvious what data is expected
+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];
+  int count = 10;
+  while(count--) {
+    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) {
+      // The following boxes are known to be power active low:
+      // 4DTV 922, Dish 622/722, Bell 9242, D*
+      if(r5kdev->power_active_low)
+        return (!(data2[1] == 0x4d));
+      else
+        return (!!(data2[1] == 0x4d));
+    }
+    usleep(100000);
+  }
+  r5000_print("R5000 failed to read power state.  Assuming ON state\n");
+  return 1;
+}
+
+int r5000_send_pwr_cmd(r5kdev_t *r5kdev, unsigned char *data)
+{
+  unsigned char data1[1]  = { 0x30 };
+  unsigned char data3[0x80];
+  int len;
+  usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000);
+  usleep(100000);
+  usb_bulk_write(r5kdev->handle, 1, data, r5kdev->button->len, 5000);
+  usleep(100000);
+  len = usb_bulk_read(r5kdev->handle, 1, data3, 2, 5000);
+  usleep(100000);
+  return len;
+}
+
+int r5000_wait_pwr(r5kdev_t *r5kdev, int on_off)
+{
+  int new_state, count = 20;
+  while(count-- && (new_state = r5000_get_power_state(r5kdev)) != on_off)
+    usleep(100000);
+  //r5000_print("End state: %s\n", !on_off ? "On" : "Off");
+  return new_state;
+}
+
+int r5000_toggle_on_off(r5kdev_t *r5kdev)
+{
+  unsigned on_off;
+  on_off = r5000_get_power_state(r5kdev);
+  if(! r5kdev->button) {
+    r5000_print("No button IR commands defined for this device!\n");
+    return on_off;
+  }
+  //r5000_print("Start state: %s\n", on_off ? "On" : "Off");
+  r5000_send_pwr_cmd(r5kdev, r5kdev->button->power);
+  on_off = r5000_wait_pwr(r5kdev, ! on_off);
+  //r5000_print("End state: %s\n", on_off ? "On" : "Off");
+  return on_off;
+}
+
+int r5000_power_on_off(r5kdev_t *r5kdev, int turn_on)
+{
+  unsigned char *pwr_command;
+  int on_off = r5000_get_power_state(r5kdev);
+  if(on_off == turn_on) {
+    return on_off;
+  }
+  if(! r5kdev->button) {
+    r5000_print("No button IR commands defined for this device!\n");
+    return on_off;
+  }
+  if(r5kdev->discrete_power) {
+    //r5000_print("Using discrete power commands\n");
+    if(turn_on) {
+      pwr_command = r5kdev->button->power_on;
+    } else {
+      pwr_command = r5kdev->button->power_off;
+    }
+  } else {
+    pwr_command = r5kdev->button->power;
+  }
+  r5000_send_pwr_cmd(r5kdev, pwr_command);
+  return r5000_wait_pwr(r5kdev, turn_on);
+}
+
+int r5000_change_channel(r5kdev_t *r5kdev, const char *chan, int mpeg_prog)
+{
+  unsigned char data2[0x80];
+  unsigned char *ptr = NULL;
+  const char *p;
+  if(! r5kdev)
+    return 0;
+  if (chan) {
+    if(! r5kdev->button) {
+      r5000_print("No button IR commands defined for this device!\n");
+    } else {
+      r5000_read_status(r5kdev, data2);
+      usb_bulk_write(r5kdev->handle, 1, r5kdev->button->clear, r5kdev->button->len, 5000);
+      usleep(r5kdev->button->delay);
+      for(p = chan; *p; p++) {
+        ptr = NULL;
+        switch(*p) {
+          case '0' : ptr = r5kdev->button->b0; break;
+          case '1' : ptr = r5kdev->button->b1; break;
+          case '2' : ptr = r5kdev->button->b2; break;
+          case '3' : ptr = r5kdev->button->b3; break;
+          case '4' : ptr = r5kdev->button->b4; break;
+          case '5' : ptr = r5kdev->button->b5; break;
+          case '6' : ptr = r5kdev->button->b6; break;
+          case '7' : ptr = r5kdev->button->b7; break;
+          case '8' : ptr = r5kdev->button->b8; break;
+          case '9' : ptr = r5kdev->button->b9; break;
+          case 'P' : r5000_power_on_off(r5kdev, 2); break;
+        }
+        if(ptr) {
+          usb_bulk_write(r5kdev->handle, 1, ptr, r5kdev->button->len, 5000);
+        }
+        usleep(r5kdev->button->delay);
+      }
+      usb_bulk_write(r5kdev->handle, 1, r5kdev->button->enter, r5kdev->button->len, 5000);
+    }
+  }
+  r5kdev->channel = mpeg_prog;
+  if(r5kdev->change_channel)
+    r5kdev->change_channel(r5kdev);
+  return 1;
+}
+
+int r5000_find_stbs(r5kenum_t *devs)
+{
+  devs->count = 0;
+  if(! r5000_usb_init) {
+    r5000_print("R5000 was not initialized before r5000_find_stbs().  Please call r5000_init() first\n");
+    return 0;
+  }
+  devs->count = r5000_dev_map.count;
+  memcpy(devs->serial, r5000_dev_map.serial, 8 * r5000_dev_map.count);
+  return 1;
+}
Index: libs/libmythtv/r5000/r5000.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5000.h	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,51 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R5000_H
+#define R5000_H
+
+#ifndef r5kdev_t
+#define r5kdev_t void
+#endif
+
+#define R5K_MAX_DEVS 10
+typedef struct {
+  unsigned char serial[R5K_MAX_DEVS][8];
+  int count;
+} r5kenum_t;
+
+typedef enum {
+  R5K_STB_VIP211 = 0,
+  R5K_STB_DIRECTV,
+  R5K_STB_HDD,
+  R5K_STB_DSR,
+  R5K_STB_VIP622,
+  R5K_STB_DISH6000,
+  R5K_STB_MAX,
+} r5ktype_t;
+
+extern int r5000_init(void (*_msgcb)(char *str));
+extern r5kdev_t *r5000_open(r5ktype_t type, unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, const char *serial);
+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 int r5000_power_on_off(r5kdev_t *r5kdev, int turn_on);
+extern int r5000_change_channel(r5kdev_t *r5kdev, const char *chan, int mpeg_prog);
+extern int r5000_find_stbs(r5kenum_t *devs);
+#endif //R5000_H
Index: libs/libmythtv/r5000/r5000_internal.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5000_internal.h	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,122 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R5000_INT_H
+#define R5000_INT_H
+
+#include <usb.h>
+#include <linux/usbdevice_fs.h>
+
+#define PRINTHEX(str, data, len) if(1) do { \
+  int _i; \
+  fprintf(stderr, str); \
+  for(_i = 0; _i < (len); _i++) { \
+    fprintf(stderr, "%02x ", (data)[_i]); \
+    if((_i % 16) == 15) fprintf(stderr, "\n"); \
+  } \
+  if(_i % 16) fprintf(stderr, "\n"); \
+} while(0)
+
+#define R5K_MAX_BUTTON_SIZE 0x80
+#define R5K_MAX_PIDS 10
+#define IS_VIDEO(x) ((x) == 0x02 || (x) == 0x1b || (x) == 0x80)
+
+struct r5k_descriptor {
+  unsigned char d[10];
+};
+
+struct r5k_epid {
+  int pid;
+  unsigned char id;
+  struct r5k_descriptor desc;
+};
+
+struct r5000_buttons {
+  int len;
+  int delay;
+  unsigned char b0[R5K_MAX_BUTTON_SIZE];
+  unsigned char b1[R5K_MAX_BUTTON_SIZE];
+  unsigned char b2[R5K_MAX_BUTTON_SIZE];
+  unsigned char b3[R5K_MAX_BUTTON_SIZE];
+  unsigned char b4[R5K_MAX_BUTTON_SIZE];
+  unsigned char b5[R5K_MAX_BUTTON_SIZE];
+  unsigned char b6[R5K_MAX_BUTTON_SIZE];
+  unsigned char b7[R5K_MAX_BUTTON_SIZE];
+  unsigned char b8[R5K_MAX_BUTTON_SIZE];
+  unsigned char b9[R5K_MAX_BUTTON_SIZE];
+  unsigned char clear[R5K_MAX_BUTTON_SIZE];
+  unsigned char enter[R5K_MAX_BUTTON_SIZE];
+  unsigned char power[R5K_MAX_BUTTON_SIZE];
+  unsigned char power_on[R5K_MAX_BUTTON_SIZE];
+  unsigned char power_off[R5K_MAX_BUTTON_SIZE];
+};
+
+struct r5kdev {
+  usb_dev_handle *handle;
+  unsigned char serial[8];
+  void *urbblk;
+  struct usbdevfs_urb **urbs;
+  unsigned char *buffer;
+  int stb_type;
+  int read_words;
+  void (*process_block)(struct r5kdev *r5kdev, unsigned char *buf, int len);
+  void (*start_stream)(struct r5kdev *r5kdev);
+  void (*change_channel)(struct r5kdev *r5kdev);
+  void *stbdata;
+  unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data);
+  void *cb_data;
+  int nexturb;
+  int streaming;
+  int bytes_read;
+  struct r5000_buttons *button;
+  int power_active_low;
+  int discrete_power;
+  int channel;
+  unsigned char pmt_pkt[188];
+  unsigned char num_pmt_entries;
+  unsigned char pmt_state;
+  unsigned char pmt_next_cc;
+  unsigned char pmt_version;
+  struct r5k_epid pmt[R5K_MAX_PIDS];
+} r5kdev_t;
+#define r5kdev_t struct r5kdev
+
+#include "r5000.h"
+
+extern void r5000_print(const char *fmt, ...);
+extern unsigned char r5000_pat_pkt[188];
+extern struct r5k_descriptor r5000_pmt_audio_desc;
+extern struct r5k_descriptor r5000_pmt_video_desc;
+extern void r5000_reset_pmt(r5kdev_t *r5kdev);
+extern void r5000_send_pmt(r5kdev_t *r5kdev);
+
+//Support for DirecTV and Dish/BEV 6000 boxes
+extern void pes_init(r5kdev_t *r5kdev);
+extern void pes_free(r5kdev_t *r5kdev);
+
+//Support for ViP series Dish Network boxes
+extern void vip_init(r5kdev_t *r5kdev);
+extern void vip_free(r5kdev_t *r5kdev);
+
+//Support for HDD and DSR series satellite/cable boxes
+extern void sat_init(r5kdev_t *r5kdev);
+extern void sat_free(r5kdev_t *r5kdev);
+
+//Buttons
+extern struct r5000_buttons vip_button_cmd;
+extern struct r5000_buttons directv_button_cmd;
+extern struct r5000_buttons dish6000_button_cmd;
+#endif
Index: libs/libmythtv/r5000/r5k_vip.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5k_vip.c	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,201 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//Support for Dish Network ViP211/ViP422 boxes
+#include <stdio.h>
+#include <string.h>
+#include "r5000_internal.h"
+
+struct r5000_vip {
+  unsigned char leftover[188];
+  int offset;
+  int pos;
+};
+#define CHECK_CONTINUITY 1
+#ifdef CHECK_CONTINUITY
+  static unsigned char continuity[0x2000];
+#endif
+void vip_add_pmt(r5kdev_t *r5kdev, int pid, int table_id)
+{
+  int i;
+  struct r5000_vip *vip = (struct r5000_vip *)r5kdev->stbdata;
+
+  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
+      r5000_reset_pmt(r5kdev);
+      break;
+    }
+    if(is_video) {
+      if(IS_VIDEO(r5kdev->pmt[i].id)) {
+        //a video entry already exists.  Reset
+        r5000_reset_pmt(r5kdev);
+        break;
+      }
+    }
+  }
+  //Didn't find this PID, add it
+  if(i == R5K_MAX_PIDS)
+    return;
+  r5000_print("Adding %04x: %02x @ %08x\n", pid, table_id, r5kdev->bytes_read + vip->pos);
+  r5kdev->pmt[r5kdev->num_pmt_entries].pid = pid;
+  r5kdev->pmt[r5kdev->num_pmt_entries].id  = table_id;
+  r5kdev->pmt[r5kdev->num_pmt_entries].desc = is_video ? r5000_pmt_video_desc : r5000_pmt_audio_desc;
+  r5kdev->num_pmt_entries++;
+  r5kdev->pmt_state |= is_video ? 0x01 : 0x02;
+}
+
+void vip_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;
+#ifdef CHECK_CONTINUITY
+  if(pid >= 0x1000) {
+    struct r5000_vip *vip = (struct r5000_vip *)r5kdev->stbdata;
+    unsigned char cont = buf[3] & 0x0f;
+    if(continuity[pid] != cont && (buf[3] & 0x30) != 0x20) {
+      r5000_print("Continuity (0x%04x) %d != %d @%08x\n",
+                  pid, cont, continuity[pid], r5kdev->bytes_read + vip->pos);
+    }
+    continuity[pid] = (cont + 1) & 0x0f;
+  }
+#endif
+  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) {
+        PRINTHEX("data", buf, af_size+8);
+      }
+      if(buf[5] & 0x02) {
+        // Has private data, this is MPEG4
+        vip_add_pmt(r5kdev, pid, 0x1b);
+      } else if(buf[5] & 0x10) {
+        // Has PCR and no private data, this is MPEG2
+        vip_add_pmt(r5kdev, pid, 0x02);
+      }
+    } else if((stream_id & 0xf0) == 0xc0) {
+      //Audio stream
+      vip_add_pmt(r5kdev, pid, 0x04);
+    } else if(stream_id  == 0xbd) {
+      //Audio stream
+      vip_add_pmt(r5kdev, pid, 0x81);
+    }
+  }
+}
+
+static void vip_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len)
+{
+  struct r5000_vip *vip = (struct r5000_vip *)r5kdev->stbdata;
+
+  int sync = 1;
+  if(! r5kdev->streaming)
+    return;
+  if(len <= 0)
+    return;
+
+  vip->pos = vip->offset;
+  while(vip->pos < len) {
+      if(buf[vip->pos] != 0x47 || (vip->pos <len-1 && buf[vip->pos+1] == 0xff))
+        goto nosync;
+      // If we get here, buf[vip->pos] == 0x47
+      if(vip->offset) {
+        //previous data exists and is part of a good packet
+        memcpy(vip->leftover+188-vip->offset, buf, vip->offset);
+        vip_force_pmt(r5kdev, vip->leftover);
+        vip->offset = 0;
+      }
+      if(vip->pos+188 <= len) {
+        //at least one full packet is available
+        if(vip->pos+188 < len && buf[vip->pos+188] != 0x47)
+          goto nosync;
+      } else {
+        //Out of data, but the partial packet may be ok.
+        memcpy(vip->leftover, buf+vip->pos, len-vip->pos);
+        vip->offset = 188-(len-vip->pos);
+        break;
+      }
+      //If we get here, we have a good packet
+      vip_force_pmt(r5kdev, buf+vip->pos);
+      if(! sync)
+        r5000_print("(%d) Found sync @ %08x\n", r5kdev->nexturb, r5kdev->bytes_read+vip->pos);
+      sync = 1;
+      vip->pos+=188;
+      continue;
+  nosync:
+      vip->offset=0;
+      if(sync)
+        r5000_print("(%d)Lost sync @ %08x\n", r5kdev->nexturb, r5kdev->bytes_read+vip->pos);
+      sync = 0;
+      vip->pos++;
+  }
+}
+
+static void vip_start_stream(r5kdev_t *r5kdev)
+{
+  struct r5000_vip *vip = (struct r5000_vip *)r5kdev->stbdata;
+  vip->offset = 0;
+}
+
+static void vip_change_channel(r5kdev_t *r5kdev)
+{
+  r5000_reset_pmt(r5kdev);
+}
+
+void vip_init(r5kdev_t *r5kdev)
+{
+  struct r5000_vip *vip = (struct r5000_vip *)malloc(sizeof(struct r5000_vip));
+  r5kdev->stbdata = vip;
+  r5kdev->process_block = vip_process_block;
+  r5kdev->start_stream  = vip_start_stream;
+  r5kdev->button = &vip_button_cmd;
+  r5kdev->change_channel = &vip_change_channel;
+  r5kdev->discrete_power = 1;
+  if(r5kdev->stb_type == R5K_STB_VIP622)
+    r5kdev->power_active_low = 1;
+}
+
+void vip_free(r5kdev_t *r5kdev)
+{
+  free(r5kdev->stbdata);
+}
+
Index: libs/libmythtv/r5000/r5k_misc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5k_misc.c	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,157 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "r5000_internal.h"
+
+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};
+
+
+struct r5k_descriptor r5000_pmt_audio_desc = {{0x06, 0x0a, 0x04, 0x65, 0x6e, 0x67, 0x00}};
+struct r5k_descriptor r5000_pmt_video_desc = {{0x00}};
+
+//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};
+
+static 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;
+}
+
+static void r5000_build_pmt(r5kdev_t *r5kdev)
+{
+  int i;
+  unsigned char *ptr;
+  unsigned char ts[188] = {
+  0x47, 0x40, 0x21, 0x10,
+  0x00, 0x02,
+  0xb0, 0x00,  //length
+  0x00, 0x01,
+  0xc1,        //version<<1 (5 bits) | current_next
+  0x00, 0x00,  //section/last_section
+  0xf0, 0x00,  //PCR_PID
+  0xf0, 0x00}; //Program Info Length
+
+  ts[3] = 0x10 | r5kdev->pmt_next_cc;
+
+  //Change the PMT version every time we rebuild the PMT
+  ts[10] |= r5kdev->pmt_version << 1;
+  r5kdev->pmt_version = (r5kdev->pmt_version + 1) % 32;
+
+  r5000_print("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;
+    memcpy(ptr, r5kdev->pmt[i].desc.d, r5kdev->pmt[i].desc.d[0]+1);
+    ptr += r5kdev->pmt[i].desc.d[0]+1;
+    if(IS_VIDEO(r5kdev->pmt[i].id)) {
+      ts[13] = 0xe0 | (r5kdev->pmt[i].pid >> 8);
+      ts[14] = r5kdev->pmt[i].pid & 0xff;
+    }
+  }
+  ts[7] = (ptr - ts) - 8/*header*/ + 4/*CRC*/;
+  r5000_calc_crc(ptr, ts + 5, (ptr - ts) - 5);
+  memset(ptr+4, 0xff, 188 - (ptr + 4 - ts));
+  memcpy(r5kdev->pmt_pkt, ts, 188);
+  //PRINTHEX("PMT", r5kdev->pmt_pkt, 188);
+}
+
+void r5000_reset_pmt(r5kdev_t *r5kdev)
+{
+  r5kdev->num_pmt_entries = 0;
+  r5kdev->pmt_state = 0;
+  r5kdev->pmt_pkt[0] = 0;
+}
+
+void r5000_send_pmt(r5kdev_t *r5kdev)
+{
+  if(r5kdev->pmt_pkt[0] != 0x47) {
+    r5000_build_pmt(r5kdev);
+  }
+  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);
+}
Index: libs/libmythtv/r5000/r5k_sat.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5k_sat.c	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,469 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//Support for Dish Network ViP211/ViP422 boxes
+#include <stdio.h>
+#include <string.h>
+#include "r5000_internal.h"
+
+#define DTV_PAT_PMT_COUNT 5000
+#define MAX_PKT_SIZE 272
+#define MAX_PAT_SECTIONS 1
+#define MAX_SIDS 200
+#define MAX_EPIDS 5
+
+struct pat {
+  int version;
+  unsigned char last_section;
+  unsigned char section_seen[MAX_PAT_SECTIONS];
+  unsigned int crc[MAX_PAT_SECTIONS];
+  unsigned int pmts[MAX_SIDS];
+  int pmt_count;
+};
+
+struct sids {
+  unsigned short sid;
+  unsigned int crc;
+  unsigned char seen_name;
+  struct r5k_epid epid[MAX_EPIDS];
+  unsigned char epid_count;
+};
+
+struct r5000_sat {
+  unsigned char buf[MAX_PKT_SIZE];
+  unsigned int pos;
+  int offset;
+  unsigned char sync;
+  unsigned char bytesize;
+  unsigned char sync_byte;
+  unsigned int has_sync_byte;
+  unsigned int pat_pmt_count;
+  unsigned int packet_size;
+  unsigned int allowed_packet_size[8];
+
+  unsigned int current_sid;
+  struct pat pats;
+  struct sids *sids;
+};
+
+static int sat_read_pat_pkt(unsigned char *pes, struct pat *pat, unsigned int size) {
+  unsigned int sec, end, crc, current_next;
+  int version;
+  unsigned char *ptr, last_sec;
+
+  if (pes[0] != 0x00) {
+    r5000_print("read_pat: expected PAT table 0x00 but got 0x%02x\n", pes[0]);
+    return -1;
+  }
+  end = (((pes[1] & 0x03) << 8 | pes[2]) + 3 - 4);
+  if(end > size-4) {
+    r5000_print("read_pat: invalid PAT table size (%d > %d)\n", end, size-4);
+    return -1;
+  }
+  crc = (pes[end]<<24) | (pes[end+1]<<16) | (pes[end+2]<<8) | pes[end+3];
+  version = (pes[5] >> 1) & 0x1f;
+  current_next = pes[5] & 0x01;
+  sec = pes[6];
+  last_sec = pes[7];
+  if(! current_next)
+    //ignore inactive PAT
+    return 0;
+  if(last_sec >= MAX_PAT_SECTIONS) {
+    r5000_print("read_pat: illegal section count %d > %d\n",
+             last_sec, MAX_PAT_SECTIONS);
+    return -1;
+  }
+  if (pat->version != version || last_sec != pat->last_section ||
+      pat->crc[sec] != crc) {
+    pat->version = version;
+    pat->last_section = last_sec;
+    pat->pmt_count = 0;
+    memset(pat->section_seen, 0, sizeof(pat->section_seen));
+  }
+  if(pat->section_seen[sec])
+    return 0;
+  pat->crc[sec] = crc;
+  pat->section_seen[sec] = 1;
+  for(ptr = pes + 8; ptr < pes + end; ptr += 4) {
+    int sid, pid;
+    sid = (ptr[0] << 8) | ptr[1];
+    pid = ((ptr[2] & 0x1F) << 8) | ptr[3];
+    r5000_print("found PID: %04x for sid: %d\n", pid, sid);
+    if(sid != 0) {
+      pat->pmts[pat->pmt_count++] = (sid << 16) | pid;
+    }
+  }
+  return 1;
+}
+
+static struct sids *sat_read_pmt_pkt(unsigned char *buf, struct sids *sids,
+                                     unsigned int size) {
+  //
+  // NOTE we aren't using last_sec here yet!
+  //
+
+  struct sids *sidptr = sids;
+  unsigned int count, skip, pos, crc, current_next;
+  int sid, sec, last_sec, pcrpid, epid, type;
+  if (buf[0] != 0x02) {
+    r5000_print("read_pmt expected table 0x02 but got 0x%02x\n", buf[0]);
+    return NULL;
+  }
+  count = (((buf[1] & 0x03) << 8) | buf[2]) + 3 - 4;
+  sid = (buf[3] << 8) | buf[4];
+  current_next = buf[5] & 0x01;
+  crc = (buf[count]<<24) | (buf[count+1]<<16) | (buf[count+2]<<8) | buf[count+3];
+  sec = buf[6];
+  last_sec = buf[7];
+  pcrpid = ((buf[8] & 0x1F) << 8) | buf[9];
+  skip = ((buf[10] & 0x03) << 8) | buf[11];
+  if(skip > count - 12 || count > size) {
+    r5000_print("skip: %d > count: %d - 12 || count > size: %d\n",
+           skip, count, size);
+    return NULL;
+  }
+  if(! current_next) {
+    r5000_print("read_pmt ignoring future PMT\n");
+    return NULL;
+  }
+  while(sidptr->sid != 0) {
+    if(sidptr->sid == sid)
+      break;
+    sidptr++;
+  }
+  if(sidptr->sid == 0) {
+    // We weren't expecting this sid
+    r5000_print("read_pmt found unexpected sid: %d\n", sidptr->sid);
+    return sidptr;
+  }
+  if(sidptr->crc == crc) {
+    //sid is unchanged
+    //r5000_print("read_pmt found identical crc (%08x) for %d\n", crc, sidptr->sid);
+    return NULL;
+  }
+  memset(sidptr, 0, sizeof(struct sids));
+
+  r5000_print("read_pmt: sid: %d pcrpid: %d skip: %d count: %d\n", sid, pcrpid, skip, count);
+  sidptr->sid = sid;
+  sidptr->crc = crc;
+  sidptr->epid_count = 0;
+  for(pos = 12 + skip; pos < count;) {
+    struct r5k_epid *pidptr = &sidptr->epid[sidptr->epid_count];
+    type = buf[pos];
+    epid = ((buf[pos+1] & 0x1F) << 8) | buf[pos+2];
+    skip = ((buf[pos+3] & 0x03) << 8) | buf[pos+4];
+    pidptr->pid = epid;
+    pidptr->id  = type == 0x80 ? 0x02 : type;
+    memcpy(pidptr->desc.d, buf + pos + 4, skip + 1);
+    sidptr->epid_count++;
+    r5000_print("read_pmt: epid %04x (type %02x, skip=%d) mapped to sid %d\n", epid, type, skip, sid);
+    pos += 5 + skip;
+  }
+  return sidptr;
+}
+
+void sat_find_chname(unsigned char *buf, struct sids *sids, unsigned int size) {
+  struct sids *sidptr = sids;
+  unsigned int count;
+  int sid;
+  char str[20], *strptr = str;
+  while(size) {
+    count = (((buf[1] & 0x03) << 8) | buf[2]) + 3;
+    if(buf[0] == 0x41) {
+      buf += count;
+      size -= count;
+      continue;
+    }
+    if(buf[0] == 0xc1) {
+      unsigned char *ptr = buf+16;
+      sid = (buf[7]<<8) | buf[8];
+      while(sidptr->sid != 0) {
+        if(sidptr->sid == sid)
+          break;
+        sidptr++;
+      }
+      if(sidptr->sid == 0) {
+        // We weren't expecting this sid
+        return;
+      }
+      if(sidptr->seen_name)
+        return;
+      sidptr->seen_name = 1;
+      while(*ptr >= 0x20 && *ptr < 0x7b && strptr-str < sizeof(str)-1) {
+        *strptr++ = *ptr++;
+      }
+      *strptr = 0;
+      r5000_print("sid: %d is channel %s\n", sid, str);
+      return;
+    }
+    return;
+  }
+}
+
+int sat_add_pmt(r5kdev_t *r5kdev, struct r5k_epid *epid)
+{
+  int i;
+  int is_video = IS_VIDEO(epid->id);
+
+  for(i = 0; i < r5kdev->num_pmt_entries; i++) {
+    if(r5kdev->pmt[i].pid == epid->pid) {
+      if(r5kdev->pmt[i].id == epid->id)
+        return 0;
+      //different table_id for existing pid.  Reset
+      r5000_reset_pmt(r5kdev);
+      break;
+    }
+    if(is_video) {
+      if(IS_VIDEO(r5kdev->pmt[i].id)) {
+        //a video entry already exists.  Reset
+        r5000_reset_pmt(r5kdev);
+        break;
+      }
+    }
+  }
+  //Didn't find this PID, add it
+  if(i == R5K_MAX_PIDS)
+    return 0;
+  r5000_print("Adding %04x: %02x (desc_len=%d) @ %08x\n", epid->pid, epid->id, epid->desc.d[0], r5kdev->bytes_read);
+  r5kdev->pmt[r5kdev->num_pmt_entries++] = *epid;
+  r5kdev->pmt_state |= is_video ? 0x01 : 0x02;
+  return 1;
+}
+
+void sat_process_ts(r5kdev_t *r5kdev, unsigned char *buf)
+{
+  struct r5000_sat *sat = (struct r5000_sat *)r5kdev->stbdata;
+  int pid;
+  int i, j, k;
+  pid = ((buf[1] << 8) | buf[2]) & 0x1fff;
+  if(pid == 0x1fff)
+    return;
+  if(pid == 0 && (buf[1] & 0x40)) {
+    //Always read PAT in case we changed transponders
+    if(sat_read_pat_pkt(buf+buf[4]+5, &sat->pats, 188-buf[4]-5) > 0) {
+      r5000_print("Found new PAT\n");
+      if(sat->pats.pmt_count) {
+        sat->sids = realloc(sat->sids, sizeof(struct sids)*(sat->pats.pmt_count+1));
+        memset(sat->sids, 0, sizeof(struct sids)*(sat->pats.pmt_count+1));
+        //Pre load sids so we don't overrun if the PMT changes before the PAT
+        for(i = 0; i < sat->pats.pmt_count; i++) {
+          sat->sids[i].sid = sat->pats.pmts[i]>>16;
+        }
+        sat->sids[i].sid = 0;
+        r5000_reset_pmt(r5kdev);
+      }
+    } else if(r5kdev->pmt_state == 0x03) {
+      r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
+      r5000_send_pmt(r5kdev);
+      sat->pat_pmt_count = 0;
+    }
+    return;
+  }
+  //Always reread PMT in case the pids have changed
+  for(i = 0; i < sat->pats.pmt_count; i++) {
+    if(pid == (unsigned short)(sat->pats.pmts[i])) {
+#if 0
+    {
+      char s[80];
+      FILE *fh;
+      sprintf(s, "0x%04x.ts", pid);
+      fh= fopen(s, "a");
+      fwrite(buf, 188, 1, fh);
+      fclose(fh);
+    }
+#endif
+      //r5000_print("PID: %04x - %04x (%d) %02x %02x %02x %02x %02x\n", pid, (unsigned short)(sat->pats.pmts[i]), i, buf[1], buf[2], buf[3], buf[4], buf[5]);
+      if(buf[1] & 0x40 && buf[4]+5 < 188) {
+        if(buf[buf[4]+5] == 0x02) {
+          struct sids *sidptr;
+          if((sidptr = sat_read_pmt_pkt(buf+buf[4]+5, sat->sids, 188-buf[4]-5))) {
+            if(sidptr->sid == 0) {
+              //Unexpected sid, reset PAT;
+              memset(&sat->pats, 0, sizeof(struct pat));
+            } else if(sat->current_sid == sidptr->sid) {
+              r5000_reset_pmt(r5kdev);
+              sat->current_sid = 0;
+            }
+          }
+        //} else if(buf[buf[4]+5] == 0xc1 || buf[buf[4]+5] == 0x41) {
+        //  sat_find_chname(buf+buf[4]+5, sat->sids, 188-buf[4]-5);
+        }
+      }
+      return;
+    }
+    if(! sat->current_sid) {
+      for(j = 0; j < sat->sids[i].epid_count; j++) {
+        if(pid == sat->sids[i].epid[j].pid &&
+           IS_VIDEO(sat->sids[i].epid[j].id) &&
+           (!r5kdev->channel || r5kdev->channel == sat->sids[i].sid)) {
+          //Found unencrypted video.  Choose this one
+          // Assume this is MPEG2.  Don't know what MPEG4 looks like yet
+          sat->current_sid = sat->sids[i].sid;
+          r5000_print("Found decrypted sid %d\n", sat->current_sid);
+          if (sat_add_pmt(r5kdev, &sat->sids[i].epid[j])) {
+            //This is a new Video PID
+            for(k = 0; k < sat->sids[i].epid_count; k++) {
+              if(sat->sids[i].epid[k].id == 0x81 ||
+                 sat->sids[i].epid[k].id == 0xbd) {
+                sat_add_pmt(r5kdev, &sat->sids[i].epid[k]);
+              }
+            }
+            r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
+            r5000_send_pmt(r5kdev);
+            sat->pat_pmt_count = 0;
+          }
+          r5kdev->cb(sat->buf, 188, r5kdev->cb_data);
+          return;
+        }
+      }
+    }
+  }
+  for(i = 0; i < r5kdev->num_pmt_entries; i++) {
+    if(pid == r5kdev->pmt[i].pid) {
+      r5kdev->cb(sat->buf, 188, r5kdev->cb_data);
+      sat->pat_pmt_count++;
+      return;
+    }
+  }
+#if 0
+  //r5000_print("Ignoring PID: %04x\n", pid);
+  {
+    char s[80];
+    FILE *fh;
+    sprintf(s, "0x%04x.ts", pid);
+    fh= fopen(s, "a");
+    fwrite(buf, 188, 1, fh);
+    fclose(fh);
+  }
+#endif
+}
+
+static void sat_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len)
+{
+  struct r5000_sat *sat = (struct r5000_sat *)r5kdev->stbdata;
+
+  int pos;
+  if(! r5kdev->streaming)
+    return;
+  if(len <= 0)
+    return;
+
+  for(pos = sat->offset; pos < len; pos += sat->bytesize) {
+    if(! sat->sync) {
+      if(buf[pos] == 0x47) {
+        int i;
+        if (pos + (sat->allowed_packet_size[0]<<1) < len) {
+          if((buf[pos+1] & 0xfc) == 0xfc && (buf[pos+3] & 0xfc) == 0xfc &&
+             (buf[pos+5] & 0xfc) == 0xfc && (buf[pos+7] & 0xfc) == 0xfc) {
+             sat->bytesize = 2;
+          }
+          for(i=0; sat->allowed_packet_size[i] != 0; i++) {
+            if(buf[pos+(sat->allowed_packet_size[i] * sat->bytesize)] == 0x47) {
+              r5000_print("(%d) Found %d byte sync at %08x: bytesize = %d\n",
+                    r5kdev->nexturb, sat->allowed_packet_size[i],
+                    r5kdev->bytes_read+pos, sat->bytesize);
+              sat->packet_size = sat->allowed_packet_size[i];
+              sat->sync = 1;
+              sat->buf[0] = 0x47;
+              sat->pos = 1;
+              break;
+            }
+          }
+        }
+      }
+      continue;
+    }
+    if (sat->pos == 0 && buf[pos] != 0x47) {
+      sat->sync = 0;
+      sat->bytesize = 1;
+      r5000_print("(%d)Lost sync at %08x\n", r5kdev->nexturb,
+             r5kdev->bytes_read+pos);
+      continue;
+    }
+    if(sat->pos == 3 && (buf[pos] & 0xc0) != 0x00) {
+      // Encrypted channel, skip this packet
+      sat->pos = 0;
+      pos += sat->bytesize * (sat->packet_size - 4); //Loop adds additional 2
+      continue;
+    }
+    sat->buf[sat->pos++] = buf[pos];
+    if (sat->pos == sat->packet_size) {
+      sat_process_ts(r5kdev, sat->buf);
+      //if packet size > 188, assume remaining bytes are parity and ignore
+      sat->pos = 0;
+    }
+  }
+  sat->offset = pos - len;
+  if(r5kdev->pmt_state == 0x03 && sat->pat_pmt_count > DTV_PAT_PMT_COUNT) {
+    r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
+    r5000_send_pmt(r5kdev);
+    sat->pat_pmt_count = 0;
+  }
+}
+
+static void sat_start_stream(r5kdev_t *r5kdev)
+{
+  struct r5000_sat *sat = (struct r5000_sat *)r5kdev->stbdata;
+  sat->offset = 0;
+  sat->sync = 0;
+  sat->pos = 0;
+  sat->bytesize = 1;
+
+  //Clear any defined PAT or PMT data
+  if(sat->sids) {
+    free(sat->sids);
+    sat->sids = 0;
+  }
+  memset(&sat->pats, 0, sizeof(struct pat));
+  sat->pat_pmt_count = DTV_PAT_PMT_COUNT;
+}
+
+static void sat_change_channel(r5kdev_t *r5kdev)
+{
+  r5000_reset_pmt(r5kdev);
+}
+
+void sat_init(r5kdev_t *r5kdev)
+{
+  struct r5000_sat *sat =
+                   (struct r5000_sat *)calloc(1, sizeof(struct r5000_sat));
+  r5kdev->stbdata = sat;
+  sat->pat_pmt_count = DTV_PAT_PMT_COUNT;
+  if(r5kdev->stb_type == R5K_STB_HDD) {
+    sat->sync_byte = 0xff;
+    sat->has_sync_byte = 1;
+    sat->allowed_packet_size[0] = 272;
+    sat->allowed_packet_size[1] = 233;
+    sat->allowed_packet_size[2] = 204;
+    sat->allowed_packet_size[3] = 188;
+    sat->allowed_packet_size[4] = 0;
+  } else {
+    sat->allowed_packet_size[0] = 188;
+    sat->allowed_packet_size[1] = 0;
+  }
+  r5kdev->process_block = sat_process_block;
+  r5kdev->start_stream  = sat_start_stream;
+  r5kdev->change_channel = &sat_change_channel;
+}
+
+void sat_free(r5kdev_t *r5kdev)
+{
+  struct r5000_sat *sat = (struct r5000_sat *)r5kdev->stbdata;
+  if(sat->sids)
+    free(sat->sids);
+  free(r5kdev->stbdata);
+}
+
Index: libs/libmythtv/r5000/r5000init.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5000init.h	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,77 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef R5000_INIT_H
+#define R5000_INIT_H
+
+#define R5K_INIT_MAX 9
+#define R5K_INIT_SERIAL 8
+#define R5K_DEFAULT_SLEEP 100000
+struct {
+  int rsleep;
+  int rlen;
+  int wsleep;
+  int wlen;
+  unsigned char data[0x40];
+} r5kinit[R5K_INIT_MAX] = {
+// 0
+{R5K_DEFAULT_SLEEP, -1, 0, 64,
+    {0x30}},
+// 1
+{R5K_DEFAULT_SLEEP, 1, 0, 64,
+    {0x08, 0x00, 0x20, 0x00, 0x00, 0x3a, 0xd4, 0x29, 0x7c, 0x56, 0x31, 0x44, 0x86, 0x6d, 0x0d, 0x0d,
+     0x1b, 0x0a, 0xad, 0x0f, 0xd0, 0x2e, 0x94, 0x3f, 0xd4, 0x08, 0xa2, 0x4b, 0x68, 0x14, 0x1f, 0x13,
+     0x04, 0x62, 0x1b, 0x14, 0xb9, 0x69, 0xcc, 0x25, 0x91, 0x06, 0xc9, 0x26, 0xf9, 0x41, 0x64, 0x46,
+     0x7d, 0x17, 0x61, 0x09, 0x5c, 0x5b, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+// 2
+{R5K_DEFAULT_SLEEP, 1, 0, 64,
+    {0x08, 0x00, 0x5a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+// 3
+{R5K_DEFAULT_SLEEP, 1, 0, 64,
+    {0x08, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+// 4
+{R5K_DEFAULT_SLEEP, 1, R5K_DEFAULT_SLEEP, 64,
+    {0x08, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+// 5
+{R5K_DEFAULT_SLEEP, 26, 0, 6,
+    {0x08, 0x01, 0x00, 0x00, 0x01, 0x14}},
+// 6
+{R5K_DEFAULT_SLEEP, 1, 0, 64,
+    {0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+// 7
+{R5K_DEFAULT_SLEEP, 22, 0, 64,
+    {0x08, 0x01, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+// 8
+{R5K_DEFAULT_SLEEP, 4, 0, 1,
+    {0x20}}
+};
+
+#endif
Index: contrib/r5000/ehci-2.6.25.patch
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ contrib/r5000/ehci-2.6.25.patch	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,11 @@
+--- a/drivers/usb/host/ehci-q.c	2007-06-11 11:37:06.000000000 -0700
++++ b/drivers/usb/host/ehci-q.c	2008-02-05 19:46:08.000000000 -0800
+@@ -751,7 +751,7 @@
+ 			info2 |= (EHCI_TUNE_MULT_HS << 30);
+ 		} else if (type == PIPE_BULK) {
+ 			info1 |= (EHCI_TUNE_RL_HS << 28);
+-			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
++			info1 |= ((maxp == 1024) ? 1024 : 512) << 16;	/* usb2 fixed maxpacket */
+ 			info2 |= (EHCI_TUNE_MULT_HS << 30);
+ 		} else {		/* PIPE_INTERRUPT */
+ 			info1 |= max_packet (maxp) << 16;
Index: contrib/r5000/r5000.hex
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ contrib/r5000/r5000.hex	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,512 @@
+:10000000020BBEAAAAAAAAAAAAAAAA020EFBAAAA76
+:10001000AAAAAA020E76AAAAAAAAAA0208B8AAAAF4
+:10002000AAAAAAAAAAAAAAAAAAAAAA020B31AAAAF0
+:10003000AAAAAA020FDEAAAAAAAAAAAAAAAAAAAA2F
+:10004000AAAAAA020800AAAAAAAAAA02069DAAAA5D
+:10005000AAAAAA020800AAAAAAAAAAAAAAAAAAAAF4
+:10006000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF0
+:10007000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE0
+:1000800090E6B9E0700302015B14700302020424DD
+:10009000FE700302029924FB7003020155147003E1
+:1000A00002014F147003020143147003020149243A
+:1000B000056003020305120FE6400302031190E6F8
+:1000C000BBE024FE602C14604724FD6016146031F0
+:1000D00024067065E52490E6B3F0E52590E6B4F0DB
+:1000E000020311E52C90E6B3F0E52D90E6B4F002A2
+:1000F0000311E52690E6B3F0E52790E6B4F002039D
+:1001000011E52890E6B3F0E52990E6B4F00203117A
+:1001100090E6BAE0FF120ECFAA06A9077B01EA49D2
+:10012000600DEE90E6B3F0EF90E6B4F002031190AC
+:10013000E6A0E04401F002031190E6A0E04401F0E3
+:10014000020311120FA7020311120FD6020311129C
+:100150000FCE020311120F95020311120FE8400394
+:1001600002031190E6B8E0247F602B14603C240267
+:1001700060030201FAA200E433FF25E0FFA204E4D9
+:10018000334F90E740F0E4A3F090E68AF090E68BDE
+:100190007402F0020311E490E740F0A3F090E68AC5
+:1001A000F090E68B7402F002031190E6BCE0547EFE
+:1001B000FF7E00E0D3948040067C007D0180047CBB
+:1001C000007D00EC4EFEED4F24C4F582740F3EF529
+:1001D00083E493FF3395E0FEEF24A1FFEE34E68F36
+:1001E00082F583E0540190E740F0E4A3F090E68AC2
+:1001F000F090E68B7402F002031190E6A0E0440157
+:10020000F0020311120FEA400302031190E6B8E076
+:1002100024FE601D2402600302031190E6BAE0B4DC
+:100220000105C20002031190E6A0E04401F00203C0
+:100230001190E6BAE0705990E6BCE0547EFF7E0073
+:10024000E0D3948040067C007D0180047C007D002A
+:10025000EC4EFEED4F24C4F582740F3EF583E4931B
+:10026000FF3395E0FEEF24A1FFEE34E68F82F583A5
+:10027000E054FEF090E6BCE05480FF131313541FCB
+:10028000FFE0540F2F90E683F0E04420F0020311CA
+:1002900090E6A0E04401F08078120FEC507390E6F5
+:1002A000B8E024FE60202402706790E6BAE0B40152
+:1002B00004D200805C90E6BAE06402605490E6A04C
+:1002C000E04401F0804B90E6BCE0547EFF7E00E00D
+:1002D000D3948040067C007D0180047C007D00EC8E
+:1002E0004EFEED4F24C4F582740F3EF583E493FF78
+:1002F0003395E0FEEF24A1FFEE34E68F82F583E034
+:100300004401F0800C120FEE500790E6A0E044018B
+:10031000F090E6A0E04480F022E4F517F516F5151C
+:10032000F514C205C200C204C201120A9D7E0A7FF2
+:10033000008E248F25752C0A752D1275220A7523BF
+:100340001C752A0A752B43752F0A753071EE54E01F
+:10035000700302045D7518007519808E1A8F1BC317
+:10036000749B9FFF740A9ECF2402CF3400FEE48F5B
+:10037000138E12F511F510F50FF50EF50DF50CAF06
+:1003800013AE12AD11AC10AB0FAA0EA90DA80CC381
+:10039000120E105026E519250FF582E518350EF5D9
+:1003A0008374CDF0E50F2401F50FE4350EF50EE46E
+:1003B000350DF50DE4350CF50C80C4E4F50FF50EA4
+:1003C000F50DF50CAF13AE12AD11AC10AB0FAA0EBC
+:1003D000A90DA80CC3120E105031AE0EAF0FE51BC5
+:1003E0002FF582E51A3EF583E0FDE5192FF582E54C
+:1003F000183EF583EDF0EF2401F50FE43EF50EE431
+:10040000350DF50DE4350CF50C80B98518248519EA
+:100410002574002480FF740A34FFFEC3E52D9FF588
+:100420002DE52C9EF52CC3E5279FF527E5269EF5A7
+:1004300026C3E5299FF529E5289EF528C3E5239FD6
+:10044000F523E5229EF522C3E52B9FF52BE52A9E99
+:10045000F52AC3E5309FF530E52F9EF52FD2E8430E
+:10046000D82090E668E04409F0E04402F090E65EAF
+:10047000E0440CF043E80443E80290E6507404F0D2
+:10048000000000E4F5B290E67AF043B288F58043CC
+:10049000A82E438804438910758B6F758DFE90E6F6
+:1004A0008F04F075AF07759DE1E4F59E90E65CE082
+:1004B000443DF0D2AF90E680E020E105D207120E75
+:1004C0004790E680E04408F00000000000000000D3
+:1004D00000E054F7F0538EF8C20530010512008099
+:1004E000C201300529120FE25024C2051207DB2099
+:1004F000001690E682E030E704E020E1EF90E6822B
+:10050000E030E604E020E0E4120EA3120FE4120F44
+:10051000F080C7C0E0C0F0C083C082C0D075D000FA
+:10052000C000C001C002C003C004C005C006C007AF
+:10053000759AE7759B80759DE130060302061A7572
+:100540000A00750B0090E67BE0FF7432250BF8A6DD
+:1005500007050BE50B7002050AE59B2480C3940692
+:1005600040E3E532120E2105F900058908059F10C8
+:1005700005DF2005B93005D240061250060A600595
+:10058000DACC05CCFF0000061A159B5391EF90E6DC
+:100590005F7408F090E68DE4F0120D670206827435
+:1005A000FD259BF59B5391EF90E65F7408F090E674
+:1005B0008DE4F0120D6702068290E7C0740AF0A382
+:1005C000E580F090E68F7402F00206745380F70223
+:1005D000067490E68F7401F08040753900803B907E
+:1005E000E7C074DDF0A37431F0A3742EF0A3743669
+:1005F000F090E68F7404F0807B53A8F785368A75F7
+:10060000CDFE75CC6F759E00801090E618740DF0CD
+:10061000806290E618740CF0805A90E67BE090E6D9
+:100620007CF0E59B2480FF90E68DE0FEEFC39E40CA
+:10063000E9E53324FEFFE59EC39F5006E4F0D206B1
+:100640008032C206759DE1759E00438902758E0059
+:10065000858A8C75C800E5367006E53542808005D0
+:10066000E535F4528043800890E67CE0F538438815
+:100670001043C8045391EF90E65F7408F090E68D44
+:10068000E4F0D007D006D005D004D003D002D001CA
+:10069000D000D0D0D082D083D0F0D0E032C0E0C043
+:1006A00083C082C0D075D000C000C004C005C006A1
+:1006B000C0075391DF90E678E05404FF7E003002DB
+:1006C0000BE0F430E1067C007D0180047C007D00BD
+:1006D000EC4EFEED4F4E6008E4FF12096F0207C8B2
+:1006E000E53224F860030207C8E53314604904606A
+:1006F000030207C8E59B2480FFBF050B059B90E61E
+:1007000079E534F00207C8E5372406FFE433FEAD8F
+:100710009BED2480FDE434FFFCC3ED9FEE6480F884
+:10072000EC648098500B90E67BE090E679F002074D
+:10073000C81209660207C8E536701CE59B2480C311
+:100740009406500B059B90E679E534F00207C875D6
+:100750003601120D67807130020F90E679E075085E
+:1007600000F509C202059B805FE5372406FFE433EC
+:10077000FEAD9BED2480FDE434FFFCC3ED9FEE64F1
+:1007800080F8EC648098503DE5372405FFE59B2414
+:1007900080B5071490E678E04440F090E679E09068
+:1007A000E67BF07F0112096FE5372404FFE59B2407
+:1007B00080B5070790E678E04420F090E679E09075
+:1007C000E67BF08003120966D007D006D005D0047E
+:1007D000D000D0D0D082D083D0E03290E682E04406
+:1007E000C0F090E681F04387010000000000227411
+:1007F00000F58690FDA57C05A3E582458370F9226E
+:10080000020F3900020F7F00020F6900020F510032
+:10081000020DA200020DD900020FF100020FF2003A
+:10082000020FF300020FF400020C4A00020513004D
+:10083000020FF500020FF600020FF700020FF8009A
+:10084000020FF900020FF200020FFA00020FFB0084
+:10085000020FFC00020FFD00020FFE00020FFF005E
+:1008600002100000020FF200020FF200020FF2006D
+:100870000210010002100200021003000210040026
+:10088000020F1C00021005000210060002100700F3
+:10089000021008000210090002100A0002100B00EA
+:1008A00002100C0002100D0002100E0002100F00CA
+:1008B0000210100002101100C0E0C083C082C0D03E
+:1008C0005388BF758B6F758DFEE59EC3947A507209
+:1008D000300313E58020E10E43800890E67CE53884
+:1008E000F0753800C203200313E58030E10E538019
+:1008F000F790E67CE538F0753800D203E538F470FF
+:100900003AE59EC3947A503390E67CE538F075382A
+:1009100000E4F00521E52194004020E59E94185064
+:100920001A759E00752100753800B2035388BF7593
+:100930003D0090E65EE04404F080224388400538A4
+:10094000801B53A8F75388F75388BF753800C2033C
+:10095000752100753D0290E65EE04404F0D0D0D0F1
+:1009600082D083D0E03290E678E04440F07F01EF1F
+:1009700014603E0460030209FF90E7C074FFF0A317
+:10098000E59BF090E678E090E7C2F090E678E0F43E
+:1009900030E604E04440F0E490E679F00000000026
+:1009A000000090E678E090E7C3F090E68F7405F0E1
+:1009B00022E533700D90E7C07410F090E68F74015B
+:1009C000F022759B80759DE7759EC090E67BE09058
+:1009D000E67CF0E5372406FFE433FEAD9BED248092
+:1009E000FDE434FFFCC3ED9FEE6480F8EC64809876
+:1009F00040D9E537240690E68FF05380F7D20222E3
+:100A00001201000200000040470502100000010230
+:100A100000010A0600020000004001000902270050
+:100A2000010100A0320904000003FF0000000705D7
+:100A30000102400000070581024000000705820214
+:100A400000040009022E00010100A0320904000088
+:100A500004FF000000070502024000000705040231
+:100A6000400000070586024000000705880240009C
+:100A7000000403090410034E00650078007400634D
+:100A8000006F006D001603480044002D0055005310
+:100A90000042002000440056005200000090E60B87
+:100AA0007403F000000090E6047480F0000000740D
+:100AB00002F000000014F0000000E4F000000090DC
+:100AC000E6007412F090E6017443F090E61074A012
+:100AD000F090E68D7401F090E61174A0F090E618A5
+:100AE000740DF090E6137420F090E614F090E61583
+:100AF000F090E61274E8F0E490E602F00000009056
+:100B0000E603F090E670F090E609F000000090E651
+:100B1000207404F0000000E490E621F00000009052
+:100B2000E630749AF0000000E490E631F000000036
+:100B300022C0E0C083C082C0D053C8FBE538D39444
+:100B400000400D75CDFE75CC6F153843C80480622A
+:100B5000E59EC39533502790E67CE0F538E5883074
+:100B6000E40AE535F452805388EF8007E53542808A
+:100B700043881075CDFE75CC6F43C8048034759ED4
+:100B800000E537B47719753700759DE1059E753816
+:100B90000075CDFE75CC6F43881043C80480135395
+:100BA00088EF53C8FB90E68DE4F0E535F4528043BE
+:100BB000A80853C87FD0D0D082D083D0E032787FCD
+:100BC000E4F6D8FD75813D020C05020319E493A3F8
+:100BD000F8E493A34003F68001F208DFF48029E4EF
+:100BE00093A3F85407240CC8C333C4540F4420C83B
+:100BF000834004F456800146F6DFE4800B010204D2
+:100C00000810204080900FB9E47E019360BCA3FFE0
+:100C1000543F30E509541FFEE493A360010ECF5406
+:100C2000C025E060A840B8E493A3FAE493A3F8E4F5
+:100C300093A3C8C582C8CAC583CAF0A3C8C582C861
+:100C4000CAC583CADFE9DEE780BEC0E0C0F0C0836A
+:100C5000C082C0D075D000C000C001C002C003C0B7
+:100C600004C005C006C00790E65F7404F05391EF1E
+:100C7000300605120CBF802CE53D7005F59E43A89B
+:100C800008438008E53D6401601AE53DB4020512A1
+:100C90000CBF801090E7C074CCF0A3E539F090E66B
+:100CA0008F7440F0D007D006D005D004D003D00216
+:100CB000D001D000D0D0D082D083D0F0D0E0327537
+:100CC0009AE720062AE490E7C0F0A3E59EF0A3741B
+:100CD000A0F0A37402F0A37497F0E4A3F0759BC690
+:100CE000F59E90E7C1E0D3943A400CD20680087597
+:100CF0009BC0C206759E3A90E7C1E0FF90E67CE09B
+:100D000090E67BF0AE9BEEC3748094815006E59E26
+:100D1000C39F40E890E68F7440F05380F7E4F53DC0
+:100D2000228E1C8F1D90E600E054187012E51D24E1
+:100D300001FFE4351CC313F51CEF13F51D8015905E
+:100D4000E600E05418FFBF100BE51D25E0F51DE59A
+:100D50001C33F51CE51D151DAE1C7002151C4E60E4
+:100D6000051207EF80EE2290E678E0F430E62DE001
+:100D70004480F0E53224F0601C24087024E533B48C
+:100D8000010CE536B4010790E67974A1F02290E6F3
+:100D90007974A0F02290E679E534F022E4FF12099C
+:100DA0006F22C0E0C083C08290E680E030E70E850D
+:100DB0002226852327852A28852B29800C852A260B
+:100DC000852B278522288523295391EF90E65D7492
+:100DD00010F0D082D083D0E032C0E0C083C08290D7
+:100DE000E680E030E70E852226852327852A2885A0
+:100DF0002B29800C852A26852B27852228852329C7
+:100E00005391EF90E65D7420F0D082D083D0E03231
+:100E1000EB9FF5F0EA9E42F0E99D42F0E89C45F038
+:100E200022D083D082F8E4937012740193700DA3E2
+:100E3000A393F8740193F5828883E4737402936832
+:100E400060EFA3A3A380DF30070990E680E0440AA7
+:100E5000F0800790E680E04408F07FDC7E05120D0C
+:100E60002190E65D74FFF090E65FF05391EF90E61D
+:100E700080E054F7F022C0E0C083C082C0D0E59E7D
+:100E8000C3947A501543884043800890E68FE4F07D
+:100E900090E65EE054FBF0753D01D0D0D082D08367
+:100EA000D0E03290E682E030E004E020E60B90E60D
+:100EB00082E030E119E030E71590E680E04401F08F
+:100EC0007F147E00120D2190E680E054FEF022A9EE
+:100ED00007AE2FAF308F828E83A3E064037017AD0F
+:100EE0000119ED7001228F828E83E07C002FFDECD2
+:100EF0003EFEAF0580DF7E007F0022C0E0C0D0E56F
+:100F000036D394004011E58055356007E535F4523D
+:100F1000808004E5354280D0D0D0E032C0E0C0838C
+:100F2000C0825380F77539015391BF90E651E05468
+:100F3000FEF0D082D083D0E032C0E0C083C082D245
+:100F4000015391EF90E65D7401F0D082D083D0E040
+:100F500032C0E0C083C082D2055391EF90E65D7449
+:100F600008F0D082D083D0E032C0E0C083C082538A
+:100F700091EF90E65D7404F0D082D083D0E032C06F
+:100F8000E0C083C0825391EF90E65D7402F0D0829E
+:100F9000D083D0E03290E740E53CF0E490E68AF080
+:100FA00090E68B04F0D32290E740E531F0E490E640
+:100FB0008AF090E68B04F0D322C182013D00C10685
+:100FC000013900000001020203030404050590E654
+:100FD000BAE0F53CD32290E6BAE0F531D32253D8FB
+:100FE000EF32D322D322D322D322D322D322D3222D
+:100FF00022323232323232323232323232323232E1
+:1010000032323232323232323232323232323232C0
+:101010003232AAAAAAAAAAAAAAAAAAAAAAAAAAAA20
+:10102000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA20
+:10103000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA10
+:10104000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA00
+:10105000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF0
+:10106000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE0
+:10107000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD0
+:10108000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0
+:10109000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0
+:1010A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0
+:1010B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA90
+:1010C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA80
+:1010D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA70
+:1010E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA60
+:1010F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA50
+:10110000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3F
+:10111000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2F
+:10112000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1F
+:10113000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0F
+:10114000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF
+:10115000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEF
+:10116000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADF
+:10117000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACF
+:10118000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABF
+:10119000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF
+:1011A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9F
+:1011B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8F
+:1011C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7F
+:1011D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6F
+:1011E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5F
+:1011F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4F
+:10120000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3E
+:10121000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2E
+:10122000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1E
+:10123000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0E
+:10124000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFE
+:10125000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE
+:10126000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADE
+:10127000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACE
+:10128000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABE
+:10129000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE
+:1012A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9E
+:1012B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8E
+:1012C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7E
+:1012D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6E
+:1012E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5E
+:1012F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4E
+:10130000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3D
+:10131000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2D
+:10132000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1D
+:10133000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0D
+:10134000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFD
+:10135000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAED
+:10136000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADD
+:10137000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACD
+:10138000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABD
+:10139000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD
+:1013A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9D
+:1013B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D
+:1013C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7D
+:1013D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6D
+:1013E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5D
+:1013F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4D
+:10140000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3C
+:10141000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2C
+:10142000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1C
+:10143000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0C
+:10144000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFC
+:10145000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEC
+:10146000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADC
+:10147000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACC
+:10148000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABC
+:10149000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC
+:1014A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9C
+:1014B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8C
+:1014C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7C
+:1014D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6C
+:1014E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5C
+:1014F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4C
+:10150000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3B
+:10151000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2B
+:10152000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1B
+:10153000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0B
+:10154000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFB
+:10155000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEB
+:10156000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADB
+:10157000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACB
+:10158000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB
+:10159000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB
+:1015A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9B
+:1015B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8B
+:1015C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7B
+:1015D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6B
+:1015E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5B
+:1015F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4B
+:10160000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3A
+:10161000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2A
+:10162000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1A
+:10163000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0A
+:10164000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFA
+:10165000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA
+:10166000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADA
+:10167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA
+:10168000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA
+:10169000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+:1016A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9A
+:1016B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8A
+:1016C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7A
+:1016D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6A
+:1016E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5A
+:1016F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4A
+:10170000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA39
+:10171000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA29
+:10172000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA19
+:10173000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA09
+:10174000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9
+:10175000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE9
+:10176000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9
+:10177000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9
+:10178000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9
+:10179000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9
+:1017A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA99
+:1017B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA89
+:1017C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA79
+:1017D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA69
+:1017E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA59
+:1017F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA49
+:10180000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA38
+:10181000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA28
+:10182000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA18
+:10183000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA08
+:10184000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF8
+:10185000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE8
+:10186000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8
+:10187000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8
+:10188000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8
+:10189000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8
+:1018A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA98
+:1018B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA88
+:1018C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA78
+:1018D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA68
+:1018E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA58
+:1018F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA48
+:10190000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA37
+:10191000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA27
+:10192000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA17
+:10193000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA07
+:10194000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF7
+:10195000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE7
+:10196000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7
+:10197000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7
+:10198000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7
+:10199000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7
+:1019A000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA97
+:1019B000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA87
+:1019C000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA77
+:1019D000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA67
+:1019E000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA57
+:1019F000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA47
+:101A0000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA36
+:101A1000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA26
+:101A2000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA16
+:101A3000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA06
+:101A4000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF6
+:101A5000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE6
+:101A6000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6
+:101A7000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6
+:101A8000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB6
+:101A9000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6
+:101AA000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA96
+:101AB000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA86
+:101AC000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76
+:101AD000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA66
+:101AE000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA56
+:101AF000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA46
+:101B0000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA35
+:101B1000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA25
+:101B2000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA15
+:101B3000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA05
+:101B4000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF5
+:101B5000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5
+:101B6000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD5
+:101B7000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC5
+:101B8000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5
+:101B9000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5
+:101BA000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA95
+:101BB000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA85
+:101BC000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA75
+:101BD000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA65
+:101BE000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA55
+:101BF000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA45
+:101C0000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA34
+:101C1000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24
+:101C2000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA14
+:101C3000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA04
+:101C4000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF4
+:101C5000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE4
+:101C6000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4
+:101C7000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4
+:101C8000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4
+:101C9000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4
+:101CA000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA94
+:101CB000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA84
+:101CC000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA74
+:101CD000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA64
+:101CE000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA54
+:101CF000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA44
+:101D0000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA33
+:101D1000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA23
+:101D2000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA13
+:101D3000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA03
+:101D4000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF3
+:101D5000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE3
+:101D6000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3
+:101D7000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3
+:101D8000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3
+:101D9000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3
+:101DA000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA93
+:101DB000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA83
+:101DC000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA73
+:101DD000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA63
+:101DE000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA53
+:101DF000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA43
+:101E0000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA32
+:101E1000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA22
+:101E2000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA12
+:101E3000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA02
+:101E4000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF2
+:101E5000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE2
+:101E6000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2
+:101E7000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2
+:101E8000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2
+:101E9000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2
+:101EA000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA92
+:101EB000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA82
+:101EC000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA72
+:101ED000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA62
+:101EE000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA52
+:101EF000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA42
+:101F0000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA31
+:101F1000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA21
+:101F2000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA11
+:101F3000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA01
+:101F4000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF1
+:101F5000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE1
+:101F6000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1
+:101F7000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC1
+:101F8000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1
+:101F9000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1
+:101FA000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA91
+:101FB000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA81
+:101FC000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA71
+:101FD000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA61
+:101FE000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA51
+:101FF000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA41
Index: contrib/r5000/r5ktest.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ contrib/r5000/r5ktest.c	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,354 @@
+/* Copyright 2007  Alan Nisota <alannisota@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <getopt.h>
+#include "r5000/r5000.h"
+
+enum {
+  TOGGLE_POWER,
+  CHANGE_CHANNEL,
+  READ_STREAM,
+  MULTI_READ,
+  MULTI_OPEN,
+  OPEN_CLOSE,
+  SCAN_DEVICES,
+  TURN_ON,
+  TURN_OFF,
+  CHECK_POWER,
+  MAX_CMD,
+};
+char cmd_names[][20] = {
+  {"TOGGLE_POWER"},
+  {"CHANGE_CHANNEL"},
+  {"READ_STREAM"},
+  {"MULTI_READ"},
+  {"MULTI_OPEN"},
+  {"OPEN_CLOSE"},
+  {"SCAN_DEVICES"},
+  {"TURN_ON"},
+  {"TURN_OFF"},
+  {"CHECK_POWER"},
+};
+
+char stb_names[][20] = {
+  {"vip211"},
+  {"directv"},
+  {"hdd"},
+  {"dsr"},
+  {"vip622"},
+  {"dish6000"},
+  {0},
+};
+
+extern char strmfile[255];
+void help(char *cmdline) {
+  int i;
+  printf("%s <-t type> <--m command> [--c channel] [--s serial] [-h]\n", cmdline);
+  printf("\t-t/--type type     : set STB type to type.  'type' can be either\n");
+  printf("\t                     a numerical value or string.  Valid types are:\n");
+  for(i = 0; stb_names[i][0] != 0; i++) {
+    printf("\t\t%d: %s\n", i, stb_names[i]);
+  }
+  printf("\t-m/--cmd command   : set command to execute.  'command' can be either\n");
+  printf("\t                     a numerical value or string.  Valid commands are:\n");
+  for(i = 0; i < MAX_CMD; i++) {
+    printf("\t\t%d: %s\n", i, cmd_names[i]);
+  }
+  printf("\t-c/--channel       : set channel to read (this does NOT tune\n");
+  printf("\t-s/--serial serial : set serial number\n");
+  printf("\t-h/--help          : show this help message\n");
+  exit(0);
+}
+
+void printstr(char *str)
+{
+  fprintf(stderr, "%s", str);
+}
+
+static unsigned char buffer[1000189];
+static unsigned char *ptr = buffer;
+unsigned int r5000_device_tspacket_handler(unsigned char *tspacket, int len, void *callback_data)
+{
+    int fd = *(int *) callback_data;
+    if (len <= 0)
+      return 0;
+    if(memcpy(ptr, tspacket, len));
+    ptr+=len;
+    if(ptr-buffer > 1000000) {
+      write(fd, buffer, ptr-buffer);
+      ptr = buffer;
+    }
+    return 1;
+}
+
+int main(int argc, char *argv[])
+{
+  r5kdev_t *usbdev = NULL;
+  int glblfd, i, j;
+  unsigned char buf[0x80];
+  int stb = -1;
+  int cmd = -1;
+  const char *channel = NULL;
+  const char *serial = NULL;
+  int runtime = 10;
+  struct option long_options[] = {
+    {"type", required_argument, NULL, 't'},
+    {"cmd", required_argument, NULL, 'm'},
+    {"channel", required_argument, NULL, 'c'},
+    {"serial", required_argument, NULL, 's'},
+    {"time", required_argument, NULL, 'i'},
+    {"dbgfile", required_argument, NULL, 'D'},
+    {"help", no_argument , NULL, 'h'},
+    {0, 0, 0, 0}
+  };
+  while (1) {
+    char c;
+    c = getopt_long (argc, argv,
+                     "t:m:c:s:hD:i:",
+                     long_options, NULL);
+    if(c == EOF)
+      break;
+    switch(c) {
+      case 't':
+      {
+        char *ptr;
+        int i;
+        stb = strtol(optarg, &ptr, 10);
+        if(ptr == optarg) {
+          stb = -1;
+          for(i = 0; stb_names[i][0] != 0; i++) {
+            if(strncasecmp(optarg, stb_names[i], strlen(stb_names[i])) == 0) {
+              stb = i;
+              break;
+            }
+          }
+          if(stb == -1) {
+            fprintf(stderr, "Unknown STB type: %s\n", optarg);
+            exit(-1);
+          }
+        } else if(stb < 0 || stb >= R5K_STB_MAX) {
+          fprintf(stderr, "Illegal STB type: %d\n", stb);
+          exit(-1);
+        }
+        break;
+      }
+      case 'm':
+      {
+        char *ptr;
+        int i;
+        cmd = strtol(optarg, &ptr, 10);
+        if(ptr == optarg) {
+          cmd = -1;
+          for(i = 0; i < MAX_CMD; i++) {
+            if(strncasecmp(optarg, cmd_names[i], strlen(cmd_names[i])) == 0) {
+              cmd = i;
+              break;
+            }
+          }
+          if(cmd == -1) {
+            fprintf(stderr, "Unknown command: %d\n", optarg);
+            exit(-1);
+          }
+        } else if(cmd < 0 || cmd >= MAX_CMD) {
+          fprintf(stderr, "Illegal command: %d\n", cmd);
+          exit(-1);
+        }
+        break;
+      }
+      case 'c':
+      {
+        int ok = 1;
+        char *p;
+        if(! strlen(optarg)) {
+          fprintf(stderr, "Couldn't parse channel '%s'\n", optarg);
+          ok = 0;
+        }
+        for(p = optarg; *p; p++) {
+          if(*p != 'P' && *p != ',' && (*p < '0' || *p > '9')) {
+            fprintf(stderr, "Couldn't parse channel '%s'\n", optarg);
+            ok = 0;
+            break;
+          }
+        }
+        if(ok)
+          channel = optarg;
+        break;
+      }
+      case 'i':
+      {
+        char *ptr;
+        runtime = strtol(optarg, &ptr, 0);
+        if(optarg == ptr) {
+          fprintf(stderr, "Couldn't parse time '%s'\n", optarg);
+        }
+        break;
+      }
+      case 's':
+        serial = optarg;
+        break;
+      case 'h':
+        help(argv[0]);
+        break;
+      case 'D':
+        #ifdef R5K_DEBUG
+          strncpy(strmfile, optarg, 255);
+        #else
+          fprintf(stderr, "--dbgfile only supported in debug mode.\nMake sure you know what you are doing!\n");
+          exit(-1);
+        #endif
+    }
+  }
+  if(cmd == -1 || stb == -1) {
+    fprintf(stderr, "Must specify --cmd and --stb\n");
+    exit(-1);
+  }
+  r5000_init(printstr);
+  if(cmd == SCAN_DEVICES) {
+    r5kenum_t devs;
+    printf("Scanning for R5000 devices\n");
+    if(! r5000_find_stbs(&devs)) {
+      printf("Failed to initialize r5000 devices\n");
+    }
+    for(i=0; i < devs.count; i++) {
+      printf("Found: %s\n", devs.serial[i]);
+    }
+    goto end;
+  }
+  usbdev = r5000_open(stb, r5000_device_tspacket_handler, &glblfd, serial);
+  if(! usbdev) {
+    fprintf(stderr, "R5000 device could not be found/opened\n");
+    exit(-1);
+  }
+  glblfd=open("raw.ts", O_WRONLY | O_TRUNC | O_CREAT, 0666);
+  if(cmd == TOGGLE_POWER) {
+    int new_state;
+    printf("Toggling On/Off\n");
+    new_state = r5000_toggle_on_off(usbdev);
+    printf("Turned power %s\n", new_state ? "On" : "Off");
+  }
+  if(cmd == TURN_ON) {
+    int new_state;
+    printf("Turning STB On\n");
+    new_state = r5000_power_on_off(usbdev, 1);
+    printf("Turned power %s\n", new_state ? "On" : "Off");
+  }
+  if(cmd == TURN_OFF) {
+    int new_state;
+    printf("Turning STB Off\n");
+    new_state = r5000_power_on_off(usbdev, 0);
+    printf("Turned power %s\n", new_state ? "On" : "Off");
+  }
+  if(cmd == CHECK_POWER) {
+    int new_state;
+    new_state = r5000_get_power_state(usbdev);
+    printf("Power is currently %s\n", new_state ? "On" : "Off");
+  }
+  if(cmd == CHANGE_CHANNEL) {
+    if(! channel) {
+      printf("Must specify a channel when using '-m CHANGE_CHANNEL'\n");
+      exit(-1);
+    }
+    printf("Setting channel %s\n", channel);
+    r5000_change_channel(usbdev, channel, 0);
+  }
+  if(cmd == OPEN_CLOSE) {
+    int on_off;
+    printf("Doing open/close\n");
+    on_off = r5000_get_power_state(usbdev);
+    printf("State1: %d\n", on_off);
+    r5000_close(usbdev);
+    printf("Closed\n");
+    sleep(1);
+    usbdev = r5000_open(stb, r5000_device_tspacket_handler, &glblfd, serial);
+    printf("ReOpened\n");
+    on_off = r5000_get_power_state(usbdev);
+    printf("State2: %d\n", on_off);
+  }
+  if(cmd == READ_STREAM || cmd == MULTI_READ) {
+    if(channel) {
+      uint c;
+      char *ptr;
+      printf("Setting channel %d\n");
+      c = strtol(channel, &ptr, 0);
+      r5000_change_channel(usbdev, NULL, c);
+    }
+    printf("Reading stream\n");
+    r5000_start_stream(usbdev);
+    time_t t = time(NULL);
+    while (time(NULL) - t < runtime)
+    {
+      // This will timeout after 1ms regardless of data availability
+      //usleep(10000);
+      r5000_loop_iterate(usbdev, 10);
+    }
+    r5000_stop_stream(usbdev);
+  }
+  if(cmd == MULTI_READ) {
+    printf("Reading stream again\n");
+    close(glblfd);
+    glblfd=open("raw_1.ts", O_WRONLY | O_TRUNC | O_CREAT, 0666);
+    sleep(1);
+    r5000_start_stream(usbdev);
+    time_t t = time(NULL);
+    while (time(NULL) - t < 10)
+    {
+      // This will timeout after 1ms regardless of data availability
+      //usleep(10000);
+      r5000_loop_iterate(usbdev, 10);
+    }
+    r5000_stop_stream(usbdev);
+  }
+  if(cmd == MULTI_OPEN) {
+    printf("Doing multi-open\n");
+    while(usbdev) {
+      time_t t;
+      r5000_start_stream(usbdev);
+      t = time(NULL);
+      while (time(NULL) - t < 2)
+      {
+        // This will timeout after 1ms regardless of data availability
+        //usleep(10000);
+        r5000_loop_iterate(usbdev, 10);
+      }
+      r5000_stop_stream(usbdev);
+      r5000_close(usbdev);
+      printf("Closed\n");
+      sleep(1);
+      usbdev = r5000_open(stb, r5000_device_tspacket_handler, &glblfd, serial);
+      printf("ReOpened %s\n", serial);
+    }
+    r5000_start_stream(usbdev);
+    time_t t = time(NULL);
+    while (time(NULL) - t < 10)
+    {
+      // This will timeout after 1ms regardless of data availability
+      //usleep(10000);
+      r5000_loop_iterate(usbdev, 10);
+    }
+    r5000_stop_stream(usbdev);
+  }
+end:
+  r5000_close(usbdev);
+  if(ptr != buffer)
+    write(glblfd, buffer, ptr-buffer);
+  close(glblfd);
+}
Index: contrib/r5000/README
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ contrib/r5000/README	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,96 @@
+ehci-2.6.25.patch:
+  This patch is needed for all kernels earlier than 2.6.26.  It adds support
+for 1024 byte frames which the R5000 needs.  As of 2.6.26 the patch is already
+in the kernel.
+
+r5ktest:
+Compile r5ktest via:
+  gcc -g -o r5ktest -I../../libs/libmythtv r5ktest.c ../../libs/libmythtv/r5000/*.c -lusb
+
+###############################################################################
+###############################################################################
+In order to use the R5000 in linux, you must 1st load the firmware into the
+device.
+The easiest way to do this is with udev:
+1) sudo cp 85-r5000.rules /etc/udev/rules.d
+2) sudo cp r5000.hex /lib/firmware/r5000.hex
+3) Now plug in the  R5000 STB
+4) lsusb | grep Anchor
+  Bus 004 Device 013: ID 0547:1002 Anchor Chips, Inc.
+5)ensure that the usbtest module did not load:
+lsmod | grep usbtest
+If you see the usbtest module you'll need to blacklist it and/or rmmod it
+
+--------------------------------------------------------------
+If this fails at any step along the way, try the manual method:
+--------------------------------------------------------------
+
+Make sure you have the following installed:
+  lsusb (in Debian/Ubuntu this is in the usbutils package)
+  fxload
+1) Locate the device using lsusb:
+lsusb
+...
+Bus 001 Device 026: ID 04b4:8613 Cypress Semiconductor Corp. CY7C68013 EZ-USB FX2 USB 2.0 Development Kit
+2)Install the firmware (this often needs to be done via sudo/root)
+(depending on where usbfs is mounted):
+fxload -t fx2 -D /dev/bus/usb/001/026 -I r5000.hex -m 0666
+or
+fxload -t fx2 -D /proc/bus/usb/001/026 -I r5000.hex -m 0666
+(note that 001 is the Bus and 026 is the Device from lsusb)
+
+3) Ensure that the firmware loaded:
+lsusb
+...
+Bus 001 Device 028: ID 0547:1002 Anchor Chips, Inc.
+(Note that is has a completely different name now)
+
+4)ensure that the usbtest module did not load:
+lsmod | grep usbtest
+If you see the usbtest module you'll need to blacklist it and/or rmmod it
+###############################################################################
+###############################################################################
+
+Before trying to use the R5000 in mythtv, make sure it is working in r5ktest
+./r5ktest -t 0 -m 6
+Scanning for R5000 devices
+Found: xxxxxxx
+
+If you see something like:
+    R5000 initialization failed at stage 1:
+	Expected 1 bytes, but got -1 bytes
+    R5000 failed to locate any R5000 devices.  Are you sure you have
+        permissions set properly?
+Then you likely do not have permissions to access the usb device.  Try running
+as root.
+
+next do:
+./r5ktest --help
+and choose the correct type for your STB:
+   vip211 : VIP211 and VIP411
+   vip622 : VIP622, VIP722, BEV9242
+   hdd:
+   dsr:
+   directv:
+
+Now try a few commands to make sure they work properly:
+   ./r5ktest --type vip211 --cmd TURN_ON
+   ./r5ktest --type vip211 --cmd TURN_OFF
+   ./r5ktest --type vip211 --cmd CHANGE_CHANNEL -c <channel number>
+   ./r5ktest --type vip211 --cmd OPEN_CLOSE
+
+###############################################################################
+###############################################################################
+
+Configure mythtv:
+Go into myth-setup and select the R5000 device, and the relevant STB.
+Configure a Video Source
+Configure an Input
+To enter channels, the easiest way is to set up scehdules-direct with the provider/channels you receieve then import them from the Card-Input menu
+If you choose to enter them yourself, make sure to set the frequency to whatever needs to be punched into the remote to select the channel
+
+Some notes:
+Only ViP style STBs (Dish Network and BEV) and DirectTV STBs have channel-change capabilities.  Others need an external program
+
+At least on the ViP211, it is necessary to disable the auto-power-off on the STB, as the box will power off but the LED will remain on, and the R5000 module won't be able to detect teh power state properly.  I'm not sure whether this applies to other boxes or not.
+
Index: contrib/r5000/85-r5000.rules
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ contrib/r5000/85-r5000.rules	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,3 @@
+SUBSYSTEM=="usb", ACTION=="add", ENV{PRODUCT}=="4b4/8613/*", RUN+="/sbin/fxload -D %N -I /lib/firmware/r5000.hex -t fx2 -m 0666"
+SUBSYSTEM=="usb", ENV{PRODUCT}=="547/1002/*", MODE="666"
+
Index: libs/libmythtv/r5000/r5k_directv_buttons.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5k_directv_buttons.c	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,129 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//Support for DirectTV remotes
+
+#include "r5000_internal.h"
+
+struct r5000_buttons directv_button_cmd =
+{
+0x49, //len
+400000, //delay
+//button 0:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 1:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 2:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 3:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 4:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 5:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 6:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 7:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 8:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//button 9:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//Clear:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//Enter:
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+//Power
+{
+    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
+    0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
+    0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
+},
+};
Index: libs/libmythtv/r5000/r5k_vip_buttons.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5k_vip_buttons.c	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,130 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//Support for Dish Network ViP211/ViP422 remotes
+
+#include "r5000_internal.h"
+
+struct r5000_buttons vip_button_cmd =
+{
+0x40, //len
+400000, //delay
+//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,
+},
+//Power-On
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a,
+ 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+//Power-Off
+{
+ 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+ 0x04, 0x0e, 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, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+ 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
+},
+};
Index: libs/libmythtv/r5000/r5k_pes.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5k_pes.c	2009-01-01 09:29:43.000000000 -0800
@@ -0,0 +1,316 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//Support for DirecTV boxes
+#include <netinet/in.h>
+#include <string.h>
+
+#include "r5000_internal.h"
+
+#define DTV_VPID 0x1322
+#define DTV_APID 0x1333
+#define DTV_PAT_PMT_COUNT 5000
+
+struct r5000_dtv {
+  unsigned char vbuf[188*2+4];
+  unsigned char abuf[188*2+6];
+  unsigned char *video;
+  unsigned char *audio;
+  unsigned int vpos;
+  unsigned int apos;
+  unsigned int vstart;
+  unsigned int astart;
+  unsigned int video_cc;
+  unsigned int audio_cc;
+  unsigned int vstate;
+  unsigned int pic_pos;
+  int alen;
+  unsigned int pat_pmt_count;
+};
+
+//The following are used to convert DirectTV into TS format
+static int directv_make_empty_pes(unsigned char *ptr, unsigned char type)
+{
+  ptr[0] = 0x00;
+  ptr[1] = 0x00;
+  ptr[2] = 0x01;
+  ptr[3] = type;
+  ptr[4] = 0x00;
+  ptr[5] = 0x00;
+  ptr[6] = 0x80;
+  ptr[7] = 0x00; //2 MSB represent PTS/DTS flag
+  ptr[8] = 0x0a;
+  ptr[9]  = 0xff;
+  ptr[10] = 0xff;
+  ptr[11] = 0xff;
+  ptr[12] = 0xff;
+  ptr[13] = 0xff;
+  ptr[14] = 0xff;
+  ptr[15] = 0xff;
+  ptr[16] = 0xff;
+  ptr[17] = 0xff;
+  ptr[18] = 0xff;
+  return 19;
+}
+
+static void directv_make_pespts(unsigned char *outptr, unsigned int pts)
+{
+        pts = htonl(pts);
+        unsigned char *inpts = (unsigned char *)&pts;
+        outptr[0] = 0x01 |
+                    ((inpts[0] & 0xC0) >>5);
+        outptr[1] = ((inpts[0] & 0x3F) << 2) |
+                    ((inpts[1] & 0xC0) >> 6);
+        outptr[2] = 0x01 | ((inpts[1] & 0x3F) << 2) |
+                    ((inpts[2] & 0x80) >> 6);
+        outptr[3] = ((inpts[2] & 0x7F) << 1) |
+                    ((inpts[3] & 0x80) >> 7);
+        outptr[4] = 0x01 | ((inpts[3] & 0x7F) << 1);
+}
+
+static void directv_update_video_pes(unsigned char *ptr, int pos)
+{
+  //pos points at the 1st char after a pic start code
+  int picture_coding_type;
+  int hdr_len;
+  unsigned int pts1, dts1;
+  unsigned char *buf = ptr + pos;
+  picture_coding_type = (buf[1] >> 3) & 0x07;
+  hdr_len = (picture_coding_type > 1) ? 5 : 4;
+  if(buf[hdr_len + 3] == 0xb5)
+    hdr_len += 9;
+  if(buf[hdr_len + 3] == 0xb2) {
+    pts1 = ((buf[hdr_len+6] & 0x03)   << 30) +
+           ((buf[hdr_len+7] & 0x7f) << 23) +
+           ((buf[hdr_len+8])          << 15) +
+           ((buf[hdr_len+9] & 0x7f) << 8) +
+           buf[hdr_len+10];
+    dts1 = ((buf[hdr_len+13] & 0x03)   << 30) +
+           ((buf[hdr_len+14] & 0x7f) << 23) +
+           ((buf[hdr_len+15])          << 15) +
+           ((buf[hdr_len+16] & 0x7f) << 8) +
+           buf[hdr_len+17];
+    //NOTE:  This is wrong.  DSS timestamps only have a resolution of 2^32/300
+    //r5000_print("pts: %08x/%f dts: %08x/%f\n", pts1, pts1 / 27000000.0, dts1, dts1 / 27000000.0);
+    ptr[7] |= 0xc0;
+    directv_make_pespts(ptr+9, pts1/300);
+    ptr[9] |= 0x30;
+    directv_make_pespts(ptr+14, dts1/300);
+    ptr[14] |= 0x10;
+  }
+}
+
+static void directv_fix_audio_pts(unsigned char *ptr)
+{
+  unsigned int pts = ((ptr[0] & 0x06) << 29) +
+                     (ptr[1] << 22) +
+                     ((ptr[2] & 0xfe) << 14) +
+                     (ptr[3] << 7) +
+                     (ptr[4] >> 1);
+  directv_make_pespts(ptr, pts/300);
+  ptr[0] |= 0x20;
+}
+
+
+static void pes_write_ts(r5kdev_t *r5kdev, unsigned char *ptr, int len, int pid, int start, int *cc)
+{
+  int stuff = 184 - len;
+  //Note:  we know that there are 188 bytes allocated before 'ptr'
+  //       that we can use for the header
+  if(stuff > 0) {
+    int stuff1 = stuff;
+    while(stuff1 > 2) {
+      *--ptr = 0xff;
+      stuff1--;
+    }
+    if(stuff1 == 2) {
+      *--ptr = 0x00;
+    }
+    *--ptr = stuff - 1;
+    *--ptr = 0x30 | *cc;
+  } else {
+    *--ptr = 0x10 | *cc;
+  }
+  *--ptr = pid & 0xff;
+  *--ptr = (start << 6) | (pid >> 8);
+  *--ptr = 0x47;
+  r5kdev->cb(ptr, 188, r5kdev->cb_data);
+  *cc = (*cc+1) & 0x0f;
+}
+
+static void pes_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len)
+{
+  int i;
+  struct r5000_dtv *dtv = (struct r5000_dtv *)r5kdev->stbdata;
+  for(i = 0; i < len; i+=2) {
+    unsigned char data = buf[i];
+    unsigned char type = buf[i+1];
+    if(0xff == type) {
+      //video
+      dtv->video[dtv->vpos++] = data;
+      if(dtv->vpos > 4 && dtv->video[dtv->vpos-2] == 0x01 &&
+         dtv->video[dtv->vpos-3] == 0x00 && dtv->video[dtv->vpos-4] == 0x00) {
+        if (data == 0xe0) {
+          //HD video header (PES)
+          pes_write_ts(r5kdev, dtv->video, dtv->vpos - 4, DTV_VPID, dtv->vstart, &dtv->video_cc);
+          dtv->pat_pmt_count++;
+          dtv->video[0] = 0x00;
+          dtv->video[1] = 0x00;
+          dtv->video[2] = 0x01;
+          dtv->video[3] = 0xe0;
+          dtv->vpos = 4;
+          dtv->vstart = 1;
+          dtv->vstate = data;
+        } else if (r5kdev->stb_type == R5K_STB_DIRECTV &&
+                   (data == 0xb3 || data == 0x00)) {
+          if (dtv->vstate == 0xff) {
+            dtv->vstate = data;
+            pes_write_ts(r5kdev, dtv->video, dtv->vpos - 4, DTV_VPID, dtv->vstart, &dtv->video_cc);
+            dtv->pat_pmt_count++;
+            //Create a PES header, but no PTS/DTS info yet so just use stuffing bytes
+            dtv->vpos = directv_make_empty_pes(dtv->video, 0xe0);
+            dtv->video[dtv->vpos++] = 0x00;
+            dtv->video[dtv->vpos++] = 0x00;
+            dtv->video[dtv->vpos++] = 0x01;
+            dtv->video[dtv->vpos++] = data;
+            dtv->vstart = 1;
+            dtv->pic_pos = dtv->vpos;
+          }
+        }
+      }
+      if(dtv->vpos == 188) {
+        if (dtv->vstate == 0x00)
+          //We found pic frame without a PES header (SD)
+          directv_update_video_pes(dtv->video, dtv->pic_pos);
+        pes_write_ts(r5kdev, dtv->video, 184, DTV_VPID, dtv->vstart, &dtv->video_cc);
+        dtv->pat_pmt_count++;
+        dtv->video[0] = dtv->video[184];
+        dtv->video[1] = dtv->video[185];
+        dtv->video[2] = dtv->video[186];
+        dtv->video[3] = dtv->video[187];
+        dtv->vpos = 4;
+        dtv->vstart = 0;
+        dtv->vstate = 0xff;
+      }
+    } else if(0xfe == type) {
+      //audio
+      dtv->audio[dtv->apos++] = data;
+      dtv->alen--;
+      if(dtv->alen <= 0 && dtv->apos > 6 && dtv->audio[dtv->apos-3] == 0xbd && dtv->audio[dtv->apos-4] == 0x01 &&
+         dtv->audio[dtv->apos-5] == 0x00 && dtv->audio[dtv->apos-6] == 0x00) {
+        dtv->alen = (dtv->audio[dtv->apos-2] << 8) + data;
+        pes_write_ts(r5kdev, dtv->audio, dtv->apos - 6, DTV_APID, dtv->astart, &dtv->audio_cc);
+        dtv->pat_pmt_count++;
+        dtv->audio[0] = 0x00;
+        dtv->audio[1] = 0x00;
+        dtv->audio[2] = 0x01;
+        dtv->audio[3] = 0xbd;
+        dtv->audio[4] = dtv->audio[dtv->apos-2];
+        dtv->audio[5] = data;
+        dtv->apos = 6;
+        dtv->astart = 1;
+        r5kdev->pmt[1].id = 0x81; //AC3
+      } else if(dtv->alen <= 0 && dtv->apos > 6 && dtv->audio[dtv->apos-3] == 0xc0 && dtv->audio[dtv->apos-4] == 0x01 &&
+           dtv->audio[dtv->apos-5] == 0x00 && dtv->audio[dtv->apos-6] == 0x00) {
+        dtv->alen = (dtv->audio[dtv->apos-2] << 8) + data;
+        pes_write_ts(r5kdev, dtv->audio, dtv->apos - 6, DTV_APID, dtv->astart, &dtv->audio_cc);
+        dtv->pat_pmt_count++;
+        dtv->audio[0] = 0x00;
+        dtv->audio[1] = 0x00;
+        dtv->audio[2] = 0x01;
+        dtv->audio[3] = 0xc0;
+        if (r5kdev->stb_type == R5K_STB_DIRECTV) {
+          dtv->audio[4] = (dtv->alen + 3) >> 8;
+          dtv->audio[5] = (dtv->alen + 3) & 0xff;
+          dtv->audio[6] = 0x80;
+          dtv->audio[7] = 0x80;
+          dtv->audio[8] = 0x05;
+          dtv->apos = 9;
+        } else {
+          dtv->audio[4] = dtv->audio[dtv->apos-2];
+          dtv->audio[5] = data;
+          dtv->apos = 6;
+        }
+        dtv->astart = 1;
+        r5kdev->pmt[1].id = 0x04; //MP2
+      } else if(dtv->apos == 190) {
+        if(dtv->astart && dtv->audio[3] == 0xc0 && r5kdev->stb_type == R5K_STB_DIRECTV)
+          directv_fix_audio_pts(dtv->audio+9);
+        pes_write_ts(r5kdev, dtv->audio, 184, DTV_APID, dtv->astart, &dtv->audio_cc);
+        dtv->pat_pmt_count++;
+        dtv->audio[0] = dtv->audio[184];
+        dtv->audio[1] = dtv->audio[185];
+        dtv->audio[2] = dtv->audio[186];
+        dtv->audio[3] = dtv->audio[187];
+        dtv->audio[4] = dtv->audio[188];
+        dtv->audio[5] = dtv->audio[189];
+        dtv->apos = 6;
+        dtv->astart = 0;
+      }
+    }
+  }
+  if(r5kdev->pmt[1].id && dtv->pat_pmt_count > DTV_PAT_PMT_COUNT) {
+    r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
+    r5000_send_pmt(r5kdev);
+    dtv->pat_pmt_count = 0;
+  }
+}
+
+static void pes_start_stream(r5kdev_t *r5kdev)
+{
+  struct r5000_dtv *dtv = (struct r5000_dtv *)r5kdev->stbdata;
+  dtv->vstart = 0;
+  dtv->astart = 0;
+  dtv->vpos = 0;
+  dtv->apos = 0;
+  dtv->video_cc = 0;
+  dtv->audio_cc = 0;
+  dtv->vstate = 0xff;
+  dtv->pat_pmt_count = DTV_PAT_PMT_COUNT;
+}
+
+void pes_init(r5kdev_t *r5kdev)
+{
+  struct r5000_dtv *dtv = (struct r5000_dtv *)calloc(1, sizeof(struct r5000_dtv));
+  dtv->video = dtv->vbuf + 188;
+  dtv->audio = dtv->abuf + 188;
+  dtv->pat_pmt_count = DTV_PAT_PMT_COUNT;
+  dtv->vstate = 0xff;
+  r5kdev->stbdata = dtv;
+  r5kdev->pmt[0].id = 0x02; //MPEG2
+  r5kdev->pmt[0].pid = DTV_VPID;
+  r5kdev->pmt[0].desc = r5000_pmt_video_desc;
+  r5kdev->pmt[1].id = 0x00;
+  r5kdev->pmt[1].pid = DTV_APID;
+  r5kdev->pmt[1].desc = r5000_pmt_audio_desc;
+  r5kdev->num_pmt_entries = 2;
+  r5kdev->process_block = pes_process_block;
+  r5kdev->start_stream  = pes_start_stream;
+  if(r5kdev->stb_type == R5K_STB_DIRECTV) {
+    r5kdev->button = &directv_button_cmd;
+    r5kdev->power_active_low = 1;
+  } else {
+    r5kdev->button = &dish6000_button_cmd;
+    r5kdev->power_active_low = 0;
+    r5kdev->discrete_power = 1;
+  }
+  r5kdev->read_words = 1;
+}
+
+void pes_free(r5kdev_t *r5kdev)
+{
+  free(r5kdev->stbdata);
+}
Index: libs/libmythtv/r5000/r5k_dish6000_buttons.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libs/libmythtv/r5000/r5k_dish6000_buttons.c	2009-01-01 09:30:14.000000000 -0800
@@ -0,0 +1,190 @@
+/* Copyright 2008 Alan Nisota <alannisota@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//Support for Dish/BEV 6000 remotes
+
+#include "r5000_internal.h"
+
+struct r5000_buttons dish6000_button_cmd =
+{
+0x79, //len
+800000, //delay
+//button 0:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 1:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 2:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 3:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 4:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 5:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 6:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 7:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 8:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//button 9:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//Clear:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//Enter:
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//Power
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04,
+},
+//Power-On
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04,
+},
+//Power-Off
+{
+	0x00, 0x67, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x00, 0x39, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
+	0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
+	0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04,
+},
+};

