Index: configure
===================================================================
--- configure	(revision 12321)
+++ configure	(working copy)
@@ -2450,11 +2450,17 @@
 
 if test x"$firewire_cable_box" = x"yes" ; then
     firewire_cable_box="no"
-    if has_library libiec61883 -a has_library libavc1394 ; then
+    libavc_5_3="no"
+    if has_library libiec61883 -a \
+       has_library libavc1394 -a \
+       has_library librom1394; then
         if test x`which pkg-config 2>/dev/null` != x"" ; then
             if `pkg-config --atleast-version 0.5.0 libavc1394` ; then
                 if `pkg-config --atleast-version 1.0.0 libiec61883` ; then
                     firewire_cable_box="yes"
+                    if `pkg-config --atleast-version 0.5.3 libavc1394` ; then
+                        libavc_5_3="yes"
+                    fi
                 fi
             fi
         fi
@@ -3434,7 +3440,10 @@
   if test x"$darwin" = x"yes" ; then
       echo "CONFIG_MAC_AVC=$mac_avc" >>  $MYTH_CONFIG_MAK
   else
-      echo "CONFIG_FIREWIRE_LIBS=-lraw1394 -liec61883 -lavc1394" >>  $MYTH_CONFIG_MAK
+      echo "CONFIG_FIREWIRE_LIBS=-lraw1394 -liec61883 -lavc1394 -lrom1394" >>  $MYTH_CONFIG_MAK
+      if test x"$libavc_5_3" = x"yes" ; then
+          CCONFIG="$CCONFIG using_libavc_5_3"
+      fi
   fi
 fi
 
Index: libs/libmythtv/firewirechannel.cpp
===================================================================
--- libs/libmythtv/firewirechannel.cpp	(revision 12321)
+++ libs/libmythtv/firewirechannel.cpp	(working copy)
@@ -1,314 +1,214 @@
 /**
  *  FirewireChannel
- *  Copyright (c) 2005 by Jim Westfall
- *  SA3250HD support Copyright (c) 2005 by Matt Porter
- *  SA4200HD/Alternate 3250 support Copyright (c) 2006 by Chris Ingrassia
+ *  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 <iostream>
 #include "mythcontext.h"
+#include "tv_rec.h"
+#include "linuxfirewiredevice.h"
+#include "darwinfirewiredevice.h"
 #include "firewirechannel.h"
 
-class TVRec;
+#define LOC QString("FireChan(%1): ").arg(GetDevice())
+#define LOC_WARN QString("FireChan(%1), Warning: ").arg(GetDevice())
+#define LOC_ERR QString("FireChan(%1), Error: ").arg(GetDevice())
 
-#define LOC QString("FireChan: ")
-#define LOC_ERR QString("FireChan, Error: ")
-
-#ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH
-#define AVC1394_PANEL_COMMAND_PASS_THROUGH     0x000007C00
+FirewireChannel::FirewireChannel(TVRec *parent, const QString &_videodevice,
+                                 const FireWireDBOptions &firewire_opts) :
+    DTVChannel(parent),
+    videodevice(_videodevice),
+    fw_opts(firewire_opts),
+    device(NULL),
+    current_channel(0),
+    isopen(false)
+{
+    uint64_t guid = videodevice.toULongLong(NULL, 16);
+    uint subunitid = 0; // we only support first tuner on STB...
+#ifdef USING_LINUX_FIREWIRE
+    device = new LinuxFirewireDevice(
+        guid, subunitid, fw_opts.speed,
+        LinuxFirewireDevice::kConnectionP2P == (uint) fw_opts.connection);
+#elif USING_OSX_FIREWIRE
+    device = new DarwinFirewireDevice(guid, subunitid, fw_opts.speed);
 #endif
 
-#ifndef AVC1394_PANEL_OPERATION_0
-#define AVC1394_PANEL_OPERATION_0              0x000000020
-#endif
+    InitializeInputs();
+}
 
-#define DCT6200_CMD0  (AVC1394_CTYPE_CONTROL | \
-                       AVC1394_SUBUNIT_TYPE_PANEL | \
-                       AVC1394_SUBUNIT_ID_0 | \
-                       AVC1394_PANEL_COMMAND_PASS_THROUGH | \
-                       AVC1394_PANEL_OPERATION_0)
+bool FirewireChannel::SetChannelByString(const QString &channum)
+{
+    InputMap::const_iterator it = inputs.find(currentInputID);
+    if (it == inputs.end())
+        return false;
 
-// SA3250HD defines
-#define AVC1394_SA3250_OPERAND_KEY_PRESS	0xE7
-#define AVC1394_SA3250_OPERAND_KEY_RELEASE	0x67
+    // Fetch tuning data from the database.
+    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;
 
-#define SA3250_CMD0   (AVC1394_CTYPE_CONTROL | \
-                       AVC1394_SUBUNIT_TYPE_PANEL | \
-                       AVC1394_SUBUNIT_ID_0 | \
-                       AVC1394_PANEL_COMMAND_PASS_THROUGH)
-#define SA3250_CMD1   (0x04 << 24)
-#define SA3250_CMD2    0xff000000
+    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))
+    {
+        return false;
+    }
 
-// power defines
-#define AVC1394_CMD_OPERAND_POWER_STATE        0x7F
-#define STB_POWER_STATE   (AVC1394_CTYPE_STATUS | \
-                           AVC1394_SUBUNIT_TYPE_UNIT | \
-                           AVC1394_SUBUNIT_ID_IGNORE | \
-                           AVC1394_COMMAND_POWER | \
-                           AVC1394_CMD_OPERAND_POWER_STATE)
+    bool ok = false;
+    if (!(*it)->externalChanger.isEmpty())
+        ok = ChangeExternalChannel(freqid);
+    else
+    {
+        uint ichan = freqid.toUInt(&ok);
+        ok = ok && isopen && SetChannelByNumber(ichan);
+    }
 
-#define STB_POWER_ON      (AVC1394_CTYPE_CONTROL | \
-                           AVC1394_SUBUNIT_TYPE_UNIT | \
-                           AVC1394_SUBUNIT_ID_IGNORE | \
-                           AVC1394_COMMAND_POWER | \
-                           AVC1394_CMD_OPERAND_POWER_ON)
+    if (ok)
+    {
+        // Set the current channum to the new channel's channum
+        curchannelname = QDeepCopy<QString>(channum);
+        (*it)->startChanNum = QDeepCopy<QString>(channum);
+    }
 
-static bool is_supported(const QString &model)
-{
-    return ((model == "DCT-6200") ||
-            (model == "SA3250HD") ||
-	    (model == "SA4200HD"));
+    return ok;
 }
 
-FirewireChannel::FirewireChannel(FireWireDBOptions firewire_opts,
-                                 TVRec *parent)
-    : FirewireChannelBase(parent), fw_opts(firewire_opts), fwhandle(NULL)
+bool FirewireChannel::Open(void)
 {
-}
+    VERBOSE(VB_CHANNEL, LOC + "Open()");
 
-FirewireChannel::~FirewireChannel(void)
-{
-    Close();
-}
+    if (inputs.find(currentInputID) == inputs.end())
+        return false;
 
-bool FirewireChannel::SetChannelByNumber(int channel)
-{
-    // Change channel using internal changer
+    if (!device)
+        return false;
 
-    if (!is_supported(fw_opts.model))
+    if (isopen)
+        return true;
+
+    InputMap::const_iterator it = inputs.find(currentInputID);
+    if (!FirewireDevice::IsSTBSupported(fw_opts.model) &&
+        (*it)->externalChanger.isEmpty())
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR +
-                QString("Model: '%1' ").arg(fw_opts.model) +
-                "is not supported by internal channel changer.");
+                QString("Model: '%1' is not supported.").arg(fw_opts.model));
+
         return false;
     }
 
-    int dig[3];
-    dig[0] = (channel % 1000) / 100;
-    dig[1] = (channel % 100)  / 10;
-    dig[2] = (channel % 10);
+    if (!device->OpenPort())
+        return false;
 
-    if (fw_opts.model == "DCT-6200")
-    {
-        VERBOSE(VB_CHANNEL, LOC +
-                QString("Channel1: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
-                .arg(dig[0]).arg(dig[1])
-                .arg(dig[2]).arg(DCT6200_CMD0 | dig[0], 0, 16)
-                .arg(DCT6200_CMD0 | dig[1], 0, 16)
-                .arg(DCT6200_CMD0 | dig[2], 0, 16));
+    isopen = true;
 
-        for (uint i = 0; i < 3 ;i++)
-        {
-            quadlet_t cmd[2] =  { DCT6200_CMD0 | dig[i], 0x0, };
-            if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 2, 1))
-            {
-                 VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
-                 return false;
-            }
-            usleep(500000);
-        }
-    }
-    else if (fw_opts.model == "SA3250HD")
+    return true;
+}
+
+void FirewireChannel::Close(void)
+{
+    VERBOSE(VB_CHANNEL, LOC + "Close()");
+    if (isopen)
     {
-        dig[0] |= 0x30;
-        dig[1] |= 0x30;
-        dig[2] |= 0x30;
+        device->ClosePort();
+        isopen = false;
+    }
+}
 
-        quadlet_t cmd[3] =
-        {
-            SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 
-            SA3250_CMD1 | (dig[2] << 16) | (dig[1] << 8) | dig[0],
-            SA3250_CMD2,
-        };
+bool FirewireChannel::SwitchToInput(const QString &input, const QString &chan)
+{
+    int inputNum = GetInputByName(input);
+    if (inputNum < 0)
+        return false;
 
-        VERBOSE(VB_CHANNEL, LOC +
-                QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
-                .arg(dig[0] & 0xf).arg(dig[1] & 0xf)
-                .arg(dig[2] & 0xf)
-                .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
-                .arg(cmd[2], 0, 16));
+    return SetChannelByString(chan);
+}
 
-        if(!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
-        {
-            VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
-            return false;
-        }
+bool FirewireChannel::SwitchToInput(int newInputNum, bool setstarting)
+{
+    (void) setstarting;
 
-        cmd[0] = SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE;
-        cmd[1] = SA3250_CMD1 | (dig[0] << 16) | (dig[1] << 8) | dig[2];
-        cmd[2] = SA3250_CMD2;
+    InputMap::const_iterator it = inputs.find(newInputNum);
+    if (it == inputs.end() || (*it)->startChanNum.isEmpty())
+        return false;
 
-        VERBOSE(VB_CHANNEL, LOC +
-                QString("Channel3: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
-                .arg(dig[0] & 0xf).arg(dig[1] & 0xf)
-                .arg(dig[2] & 0xf)
-                .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
-                .arg(cmd[2], 0, 16));
+    return SetChannelByString((*it)->startChanNum);
+}
 
-        if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
-        {
-            VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
-            return false;
-        }
-    }
-    else if (fw_opts.model == "SA4200HD")
+QString FirewireChannel::GetDevice(void) const
+{
+    return videodevice;
+}
+
+bool FirewireChannel::SetPowerState(bool on)
+{
+    if (!isopen)
     {
-        quadlet_t cmd[3] =
-        {
-            SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
-            SA3250_CMD1 | (channel << 8),
-            SA3250_CMD2,
-        };
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "SetPowerState() called on closed FirewireChannel.");
 
-        VERBOSE(VB_CHANNEL, LOC +
-                QString("SA4200Channel: %1 cmds: 0x%2 0x%3 0x%4")
-                .arg(channel).arg(cmd[0], 0, 16)
-                .arg(cmd[1], 0, 16)
-                .arg(cmd[2], 0, 16));
-
-        if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
-        {
-            VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
-            return false;
-        }
+        return false;
     }
 
-    return true;
+    return device->SetPowerState(on);
 }
 
-bool FirewireChannel::OpenFirewire(void)
+FirewireDevice::PowerState FirewireChannel::GetPowerState(void) const
 {
-    if (!is_supported(fw_opts.model))
+    if (!isopen)
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR +
-                QString("Model: '%1' ").arg(fw_opts.model) +
-                "is not supported by internal channel changer.");
-        return false;
-    }
+                "GetPowerState() called on closed FirewireChannel.");
 
-    // Open channel
-    fwhandle = raw1394_new_handle_on_port(fw_opts.port);
-    if (!fwhandle)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle " +
-                QString("for port: %1").arg(fw_opts.port));
-        return false;
+        return FirewireDevice::kAVCPowerQueryFailed;
     }
 
-    VERBOSE(VB_CHANNEL, LOC + "Allocated raw1394 handle " +
-            QString("for port %1").arg(fw_opts.port));
+    return device->GetPowerState();
+}
 
-    // verify node looks like a stb
-    if (!avc1394_check_subunit_type(fwhandle, fw_opts.node,
-                                    AVC1394_SUBUNIT_TYPE_TUNER))
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
-                "type tuner.").arg(fw_opts.node));
-        CloseFirewire();
-        return false;
-    }
+bool FirewireChannel::Retune(void)
+{
+    VERBOSE(VB_CHANNEL, LOC + "Retune()");
 
-    if (!avc1394_check_subunit_type(fwhandle, fw_opts.node, 
-                                    AVC1394_SUBUNIT_TYPE_PANEL))
+    if (FirewireDevice::kAVCPowerOff == GetPowerState())
     {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
-                "type panel.").arg(fw_opts.node));
-        CloseFirewire();
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "STB is turned off, must be on to retune.");
+
         return false;
     }
 
-    // check power, power on if off
-    if (GetPowerState() == Off)
-    {
-        quadlet_t *rval, response, cmd = STB_POWER_ON;
-        VERBOSE(VB_IMPORTANT, LOC + QString("Powering on (cmd: 0x%1)")
-                                            .arg(cmd, 0, 16));
-        rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1);
-        if (rval)
-        {
-            response = rval[0];
+    if (current_channel)
+        return SetChannelByNumber(current_channel);
 
-            if (AVC1394_MASK_RESPONSE(response) == AVC1394_RESPONSE_ACCEPTED)
-            {
-                VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd successful "
-                                                    "(0x%1)")
-                                                    .arg(response, 0, 16));
-                // allow some time for the stb to power on
-                sleep(3);
-                if (GetPowerState() == Off)
-                {
-                    VERBOSE(VB_IMPORTANT, LOC + "STB is still off!?");
-                    return false;
-                }
-                return true;
-            }
-            else
-            {
-                VERBOSE(VB_IMPORTANT, LOC + QString("Power on cmd failed "
-                                                    "(0x%1)")
-                                                    .arg(response, 0, 16));
-                return false;
-            }
-        }
-        else
-        {
-            VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");
-            return false;
-        }
-    }
-    return true;
+    return false;
 }
 
-void FirewireChannel::CloseFirewire(void)
+bool FirewireChannel::SetChannelByNumber(int channel)
 {
-    VERBOSE(VB_CHANNEL, LOC + "Releasing raw1394 handle");
-    raw1394_destroy_handle(fwhandle);
-}
+    current_channel = channel;
 
-FirewireChannel::PowerState FirewireChannel::GetPowerState(void)
-{
-    quadlet_t *rval, response, cmd = STB_POWER_STATE;
-
-    VERBOSE(VB_CHANNEL, LOC + QString("Requesting STB Power State (cmd: 0x%1)")
-                                      .arg(STB_POWER_STATE, 0, 16));
-    rval = avc1394_transaction_block(fwhandle, fw_opts.node, &cmd, 1, 1);
-
-    if (rval)
+    if (FirewireDevice::kAVCPowerOff == GetPowerState())
     {
-        response = rval[0];
+        VERBOSE(VB_IMPORTANT, LOC_WARN +
+                "STB is turned off, must be on to set channel.");
 
-        if (AVC1394_MASK_RESPONSE(response) == AVC1394_RESPONSE_IMPLEMENTED)
-        {
-            if ((response & 0xFF) == AVC1394_CMD_OPERAND_POWER_ON)
-            {
-                VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: ON (0x%1)")
-                                                  .arg(response, 0, 16));
-                return On;
-            }
-            else if ((response & 0xFF) == AVC1394_CMD_OPERAND_POWER_OFF)
-            {
-                VERBOSE(VB_IMPORTANT, LOC + QString("STB Power State: OFF " 
-                                                    "(0x%1)")
-                                                    .arg(response, 0, 16));
-                return Off;
-            }
-            else
-            {
-                VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: "
-                                                  "Unknown Response (0x%1)")
-                                                  .arg(response, 0, 16));
-                return Failed;
-            }
-        }
-        else
-        {
-            VERBOSE(VB_CHANNEL, LOC + QString("STB Power State: Failed (0x%1)")
-                                              .arg(response, 0, 16));
-            return Failed;
-        }
+        SetSIStandard("mpeg");
+        SetCachedATSCInfo(QString("%1-1").arg(channel));
+
+        return true; // signal monitor will call retune later...
     }
-    VERBOSE(VB_CHANNEL, LOC + "Failed to get STB Power State");
-    return Failed;
+
+    if (!device->SetChannel(fw_opts.model, 0, channel))
+        return false;
+
+    SetSIStandard("mpeg");
+    SetCachedATSCInfo(QString("%1-1").arg(channel));
+
+    return true;
 }
Index: libs/libmythtv/firewirerecorderbase.h
===================================================================
--- libs/libmythtv/firewirerecorderbase.h	(revision 12321)
+++ libs/libmythtv/firewirerecorderbase.h	(working copy)
@@ -1,63 +0,0 @@
-/**
- *  FirewireRecorderBase
- *  Copyright (c) 2005 by Jim Westfall
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-#ifndef FIREWIRERECORDERBASE_H_
-#define FIREWIRERECORDERBASE_H_
-
-#include "dtvrecorder.h"
-#include "tsstats.h"
-#include "tspacket.h"
-#include "streamlisteners.h"
-
-/** \class FirewireRecorderBase
- *  \brief This is a specialization of DTVRecorder used to
- *         handle DVB and ATSC streams from a firewire input.
- *
- *  \sa DTVRecorder
- */
-class FirewireRecorderBase : public DTVRecorder,
-                             public MPEGSingleProgramStreamListener
-{
-    friend class MPEGStreamData; 
-    friend class TSPacketProcessor; 
-
-  public:
-    FirewireRecorderBase(TVRec *rec);
-    ~FirewireRecorderBase(); 
- 
-    // Commands 
-    void StartRecording(void);
-    void ProcessTSPacket(const TSPacket &tspacket);
-    bool PauseAndWait(int timeout = 100); 
-
-    // Sets
-    void SetOptionsFromProfile(RecordingProfile *profile,
-                               const QString &videodev,
-                               const QString &audiodev,
-                               const QString &vbidev);
-    void SetStreamData(MPEGStreamData*);
-
-    // Gets 
-    MPEGStreamData* StreamData(void) { return _mpeg_stream_data; }
-
-    // MPEG Single Program
-    void HandleSingleProgramPAT(ProgramAssociationTable*); 
-    void HandleSingleProgramPMT(ProgramMapTable*);
-
-  private:
-    virtual void Close() = 0;
-    virtual void start() = 0;
-    virtual void stop() = 0;
-    virtual bool grab_frames() = 0;
-
-    MPEGStreamData  *_mpeg_stream_data; 
-    TSStats          _ts_stats;   
-
-  protected: 
-    static const int  kTimeoutInSeconds; 
-};
-
-#endif
Index: libs/libmythtv/firewirechannelbase.h
===================================================================
--- libs/libmythtv/firewirechannelbase.h	(revision 12321)
+++ libs/libmythtv/firewirechannelbase.h	(working copy)
@@ -1,53 +0,0 @@
-/**
- *  FirewireChannelBase
- *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-
-#ifndef LIBMYTHTV_FIREWIRECHANNELBASE_H
-#define LIBMYTHTV_FIREWIRECHANNELBASE_H
-
-#include <qstring.h>
-#include "tv_rec.h"
-#include "channelbase.h"
-
-#include "mythconfig.h"
-
-namespace AVS
-{
-  class AVCDeviceController;
-  class AVCDevice;
-}
-
-class FirewireChannelBase : public ChannelBase
-{
-  public:
-    FirewireChannelBase(TVRec *parent)   
-        : ChannelBase(parent), isopen(false) { } 
-    ~FirewireChannelBase() { Close(); }
-
-    bool Open(void);
-    void Close(void);
-
-    // Sets
-    bool SetChannelByString(const QString &chan);
-    virtual bool SetChannelByNumber(int channel) = 0;
-
-    // Gets
-    bool IsOpen(void) const { return isopen; }
-
-    // Commands
-    bool SwitchToInput(const QString &inputname, const QString &chan);
-    bool SwitchToInput(int newcapchannel, bool setstarting)
-        { (void)newcapchannel; (void)setstarting; return false; }
-
-  private:
-    virtual bool OpenFirewire() = 0;
-    virtual void CloseFirewire() = 0;
-
-  protected:
-    bool isopen;
-};
-
-#endif
Index: libs/libmythtv/firewiredevice.cpp
===================================================================
--- libs/libmythtv/firewiredevice.cpp	(revision 0)
+++ libs/libmythtv/firewiredevice.cpp	(revision 0)
@@ -0,0 +1,541 @@
+/**
+ *  FirewireDevice
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// Qt headers
+#include <qdeepcopy.h>
+
+// MythTV headers
+#include "linuxfirewiredevice.h"
+#include "darwinfirewiredevice.h"
+#include "mythcontext.h"
+#include "pespacket.h"
+
+#define LOC      QString("FireDev(%1): ").arg(m_guid)
+#define LOC_WARN QString("FireDev(%1), Warning: ").arg(m_guid)
+#define LOC_ERR  QString("FireDev(%1), Error: ").arg(m_guid)
+
+
+AVCInfo::AVCInfo() :
+    port(-1), node(-1),
+    guid(0), specid(0), vendorid(0), modelid(0),
+    firmware_revision(0), product_name(QString::null)
+{
+}
+
+AVCInfo::AVCInfo(const AVCInfo &o) :
+    port(o.port),         node(o.node),
+    guid(o.guid),         specid(o.specid),
+    vendorid(o.vendorid), modelid(o.modelid),
+    firmware_revision(o.firmware_revision),
+    product_name(QDeepCopy<QString>(o.product_name))
+{
+}
+
+AVCInfo &AVCInfo::operator=(const AVCInfo &o)
+{
+    port     = o.port;
+    node     = o.node;
+    guid     = o.guid;
+    specid   = o.specid;
+    vendorid = o.vendorid;
+    modelid  = o.modelid;
+    firmware_revision = o.firmware_revision;
+    product_name = QDeepCopy<QString>(o.product_name);
+
+    return *this;
+}
+
+QString AVCInfo::GetGUIDString(void) const
+{
+    QString g0 = QString("%1").arg((uint32_t) (guid >> 32), 0, 16);
+    QString g1 = QString("%1").arg((uint32_t) guid, 0, 16);
+
+    while (g0.length() < 8)
+        g0 = "0" + g0;
+    while (g1.length() < 8)
+        g1 = "0" + g1;
+
+    return QDeepCopy<QString>(g0.upper() + g1.upper());
+}
+
+static void fw_init(QMap<uint64_t,QString> &id_to_model);
+
+QMap<uint64_t,QString> FirewireDevice::s_id_to_model;
+QMutex                 FirewireDevice::s_static_lock;
+
+FirewireDevice::FirewireDevice(uint64_t guid, uint subunitid, uint speed) :
+    m_guid(guid),           m_subunitid(subunitid),
+    m_speed(speed),
+    m_last_channel(0),      m_last_crc(0),
+    m_buffer_cleared(true), m_open_port_cnt(0),
+    m_lock(false)
+{
+}
+
+void FirewireDevice::AddListener(TSDataListener *listener)
+{
+    QMutexLocker locker(&m_lock);
+
+    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());
+}
+
+void FirewireDevice::RemoveListener(TSDataListener *listener)
+{
+    QMutexLocker locker(&m_lock);
+
+    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());
+}
+
+bool FirewireDevice::SetPowerState(bool on)
+{
+    QMutexLocker locker(&m_lock);
+
+    vector<uint8_t> cmd;
+    vector<uint8_t> ret;
+
+    cmd.push_back(kAVCControlCommand);
+    cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
+    cmd.push_back(kAVCUnitPowerOpcode);
+    cmd.push_back((on) ? kAVCPowerStateOn : kAVCPowerStateOff);
+
+    QString cmdStr = (on) ? "on" : "off";
+    VERBOSE(VB_RECORD, LOC + QString("Powering %1").arg(cmdStr));
+
+    if (SendAVCCommand(cmd, ret, -1))
+    {
+        VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");
+        return false;
+    }
+
+    if (kAVCAcceptedStatus != ret[0])
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("Power %1 failed").arg(cmdStr));
+
+        return false;
+    }
+
+    VERBOSE(VB_RECORD, LOC +
+            QString("Power %1 cmd sent successfully").arg(cmdStr));
+
+    return true;
+}
+
+FirewireDevice::PowerState FirewireDevice::GetPowerState(void)
+{
+    QMutexLocker locker(&m_lock);
+
+    vector<uint8_t> cmd;
+    vector<uint8_t> ret;
+
+    cmd.push_back(kAVCStatusInquiryCommand);
+    cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
+    cmd.push_back(kAVCUnitPowerOpcode);
+    cmd.push_back(kAVCPowerStateQuery);
+
+    VERBOSE(VB_CHANNEL, LOC + "Requesting STB Power State");
+
+    if (!SendAVCCommand(cmd, ret, -1))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Power cmd failed (no response)");
+        return kAVCPowerQueryFailed;
+    }
+
+    QString loc = LOC + "STB Power State: ";
+
+    if (ret[0] != kAVCResponseImplemented)
+    {
+        VERBOSE(VB_CHANNEL, loc + "Query not implemented");
+        return kAVCPowerUnknown;
+    }
+
+    // check 1st operand..
+    if (ret[3] == kAVCPowerStateOn)
+    {
+        VERBOSE(VB_CHANNEL, loc + "On");
+        return kAVCPowerOn;
+    }
+
+    if (ret[3] == kAVCPowerStateOff)
+    {
+        VERBOSE(VB_CHANNEL, loc + "Off");
+        return kAVCPowerOff;
+    }
+
+    VERBOSE(VB_IMPORTANT, LOC_ERR + "STB Power State: Unknown Response");
+
+    return kAVCPowerUnknown;
+}
+
+bool FirewireDevice::GetSubunitInfo(uint8_t table[32])
+{
+    memset(table, 0xff, 32 * sizeof(uint8_t));
+
+    for (uint i = 0; i < 8; i++)
+    {
+        vector<uint8_t> cmd;
+        vector<uint8_t> ret;
+
+        cmd.push_back(kAVCStatusInquiryCommand);
+        cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
+        cmd.push_back(kAVCUnitSubunitInfoOpcode);
+        cmd.push_back((i<<4) | 0x07);
+        cmd.push_back(0xFF);
+        cmd.push_back(0xFF);
+        cmd.push_back(0xFF);
+        cmd.push_back(0xFF);
+
+        if (!SendAVCCommand(cmd, ret, -1))
+            return false;
+
+        if (ret.size() >= 8)
+        {
+            table[(i<<2)+0] = ret[4];
+            table[(i<<2)+1] = ret[5];
+            table[(i<<2)+2] = ret[6];
+            table[(i<<2)+3] = ret[7];
+        }
+    }
+
+    return true;
+}
+
+bool FirewireDevice::SetChannel(const QString &panel_model,
+                                uint alt_method, uint channel)
+{
+    QMutexLocker locker(&m_lock);
+
+    if (!IsSTBSupported(panel_model))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("Model: '%1' ").arg(panel_model) +
+                "is not supported by internal channel changer.");
+        return false;
+    }
+
+    int digit[3];
+    digit[0] = (channel % 1000) / 100;
+    digit[1] = (channel % 100)  / 10;
+    digit[2] = (channel % 10);
+
+    if (m_subunitid >= kAVCSubunitIdExtended)
+        return false;
+
+    vector<uint8_t> cmd;
+    vector<uint8_t> ret;
+
+    if ((panel_model.upper() == "GENERIC") ||
+        (panel_model.upper() == "SA4200HD"))
+    {
+        cmd.push_back(kAVCControlCommand);
+        cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
+        cmd.push_back(kAVCPanelPassThrough);
+        cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyPress);
+
+        cmd.push_back(4); // operand length
+        cmd.push_back((channel>>8) & 0x0f);
+        cmd.push_back(channel & 0xff);
+        cmd.push_back(0x00);
+        cmd.push_back(0x00);
+
+        if (!SendAVCCommand(cmd, ret, -1))
+            return false;
+
+        bool press_ok = (kAVCAcceptedStatus == ret[0]);
+
+        cmd[3]= kAVCPanelKeyTuneFunction | kAVCPanelKeyRelease;
+        if (!SendAVCCommand(cmd, ret, -1))
+            return false;
+
+        bool release_ok = (kAVCAcceptedStatus == ret[0]);
+
+        if (!press_ok && !release_ok)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "Tuning failed");
+            return false;
+        }
+
+        SetLastChannel(channel);
+        return true;
+    }
+
+    bool is_mot = ((panel_model.upper() == "DCT-6200") ||
+                   (panel_model.upper() == "DCT-6212") ||
+                   (panel_model.upper() == "DCT-6216"));
+
+    if (is_mot && !alt_method)
+    {
+        for (uint i = 0; i < 3 ;i++)
+        {
+            cmd.clear();
+            cmd.push_back(kAVCControlCommand);
+            cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
+            cmd.push_back(kAVCPanelPassThrough);
+            cmd.push_back(kAVCPanelKey0 + digit[i] | kAVCPanelKeyPress);
+            cmd.push_back(0x00);
+            cmd.push_back(0x00);
+            cmd.push_back(0x00);
+            cmd.push_back(0x00);
+
+            if (!SendAVCCommand(cmd, ret, -1))
+                return false;
+
+            usleep(500000);
+        }
+
+        SetLastChannel(channel);
+        return true;
+    }
+
+    if (is_mot && alt_method)
+    {
+        cmd.push_back(kAVCControlCommand);
+        cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
+        cmd.push_back(kAVCPanelPassThrough);
+        cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyPress);
+
+        cmd.push_back(4); // operand length
+        cmd.push_back((channel>>8) & 0x0f);
+        cmd.push_back(channel & 0xff);
+        cmd.push_back(0x00);
+        cmd.push_back(0xff);
+
+        if (!SendAVCCommand(cmd, ret, -1))
+            return false;
+
+        SetLastChannel(channel);
+        return true;
+    }
+
+    if (panel_model.upper() == "SA3250HD")
+    {
+        cmd.push_back(kAVCControlCommand);
+        cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
+        cmd.push_back(kAVCPanelPassThrough);
+        cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyRelease);
+
+        cmd.push_back(4); // operand length
+        cmd.push_back(0x30 | digit[2]);
+        cmd.push_back(0x30 | digit[1]);
+        cmd.push_back(0x30 | digit[0]);
+        cmd.push_back(0xff);
+
+        if (!SendAVCCommand(cmd, ret, -1))
+            return false;
+
+        cmd[5] = 0x30 | digit[0];
+        cmd[6] = 0x30 | digit[1];
+        cmd[7] = 0x30 | digit[2];
+
+        if (!SendAVCCommand(cmd, ret, -1))
+            return false;
+
+        SetLastChannel(channel);
+        return true;
+    }
+
+    return false;
+}
+
+void FirewireDevice::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 FirewireDevice::SetLastChannel(const uint channel)
+{
+    m_buffer_cleared = (channel == m_last_channel);
+    m_last_channel   = channel;
+
+    VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2")
+            .arg(channel).arg(m_buffer_cleared ? "yes" : "no"));
+}
+
+void FirewireDevice::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;
+        VERBOSE(VB_RECORD, LOC +
+                QString("ProcessPATPacket: CRC 0x%1 cleared: %2")
+                .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no"));
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's");
+    }
+}
+
+QString FirewireDevice::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 QDeepCopy<QString>(ret);
+}
+
+vector<AVCInfo> FirewireDevice::GetSTBList(void)
+{
+    vector<AVCInfo> list;
+
+#ifdef USING_LINUX_FIREWIRE
+    list = LinuxFirewireDevice::GetSTBList();
+#elif USING_OSX_FIREWIRE
+    list = DarwinFirewireDevice::GetSTBList();
+#endif
+
+//#define DEBUG_AVC_INFO
+#ifdef DEBUG_AVC_INFO
+    AVCInfo info;
+    info.guid     = 0x0016928a7b600001ULL;
+    info.specid   = 0x0;
+    info.vendorid = 0x000014f8;
+    info.modelid  = 0x00001072;
+    info.firmware_revision = 0x0;
+    info.product_name = "Explorer 4200 HD";
+    list.push_back(info);
+
+    info.guid     = 0xff2145a850e39810ULL;
+    info.specid   = 0x0;
+    info.vendorid = 0x000014f8;
+    info.modelid  = 0x00000be0;
+    info.firmware_revision = 0x0;
+    info.product_name = "Explorer 3250 HD";
+    list.push_back(info);
+#endif // DEBUG_AVC_INFO
+
+    return list;
+}
+
+bool FirewireDevice::IsSubunitType(
+    const uint8_t unit_table[32], IEEE1394UnitAddress subunit_type)
+{
+    for (uint i = 0; i < 32; i++)
+    {
+        int subunit = unit_table[i];
+        if ((subunit != 0xff) &&
+            (subunit & kAVCSubunitTypeUnit) == subunit_type)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+QString FirewireDevice::GetSubunitInfoString(const uint8_t table[32])
+{
+    QString str = "Subunit Types: ";
+
+    if (IsSubunitType(table, kAVCSubunitTypeVideoMonitor))
+        str += "Video Monitor, ";
+    if (IsSubunitType(table, kAVCSubunitTypeAudio))
+        str += "Audio, ";
+    if (IsSubunitType(table, kAVCSubunitTypePrinter))
+        str += "Printer, ";
+    if (IsSubunitType(table, kAVCSubunitTypeDiscRecorder))
+        str += "Disk Recorder, ";
+    if (IsSubunitType(table, kAVCSubunitTypeTapeRecorder))
+        str += "Tape Recorder, ";
+    if (IsSubunitType(table, kAVCSubunitTypeTuner))
+        str += "Tuner, ";
+    if (IsSubunitType(table, kAVCSubunitTypeCA))
+        str += "CA, ";
+    if (IsSubunitType(table, kAVCSubunitTypeVideoCamera))
+        str += "Camera, ";
+    if (IsSubunitType(table, kAVCSubunitTypePanel))
+        str += "Panel, ";
+    if (IsSubunitType(table, kAVCSubunitTypeBulletinBoard))
+        str += "Bulletin Board, ";
+    if (IsSubunitType(table, kAVCSubunitTypeCameraStorage))
+        str += "Camera Storage, ";
+    if (IsSubunitType(table, kAVCSubunitTypeMusic))
+        str += "Music, ";
+    if (IsSubunitType(table, kAVCSubunitTypeVendorUnique))
+        str += "Vendor Unique, ";
+
+    return str;
+}
+
+static void fw_init(QMap<uint64_t,QString> &id_to_model)
+{
+    id_to_model[0x11e6ULL << 32 | 0x0be0] = "SA3250HD";
+    id_to_model[0x14f8ULL << 32 | 0x0be0] = "SA3250HD";
+    id_to_model[0x1692ULL << 32 | 0x0be0] = "SA3250HD";
+
+    id_to_model[0x11e6ULL << 32 | 0x1072] = "SA4200HD";
+    id_to_model[0x14f8ULL << 32 | 0x1072] = "SA4200HD";
+    id_to_model[0x1692ULL << 32 | 0x1072] = "SA4200HD";
+
+    const uint64_t motorolla_vendor_ids[] =
+    {   /* 6200 */
+        0x0ce5,    0x0e5c,    0x1225,    0x0f9f,    0x1180,
+        0x12c9,    0x11ae,    0x152f,    0x14e8,    0x16b5,    0x1371,
+        /* 6412 */
+        0x0f9f,    0x152f,
+        /* 6416 */
+        0x17ee,
+    };
+    const uint motorolla_vendor_id_cnt =
+        sizeof(motorolla_vendor_ids) / sizeof(uint32_t);
+
+    const uint32_t motorolla_6200model_ids[] = { 0x620a, 0x6200, };
+    const uint32_t motorolla_6212model_ids[] = { 0x64ca, 0x64cb, };
+    const uint32_t motorolla_6216model_ids[] = { 0x646b, };
+
+    for (uint i = 0; i < motorolla_vendor_id_cnt; i++)
+        for (uint j = 0; j < 2; j++)
+            id_to_model[motorolla_vendor_ids[i] << 32 |
+                        motorolla_6200model_ids[j]] = "DCT-6200";
+
+    for (uint i = 0; i < motorolla_vendor_id_cnt; i++)
+        for (uint j = 0; j < 2; j++)
+            id_to_model[motorolla_vendor_ids[i] << 32 |
+                        motorolla_6212model_ids[j]] = "DCT-6212";
+
+    for (uint i = 0; i < motorolla_vendor_id_cnt; i++)
+        for (uint j = 0; j < 2; j++)
+            id_to_model[motorolla_vendor_ids[i] << 32 |
+                        motorolla_6216model_ids[j]] = "DCT-6216";
+}
Index: libs/libmythtv/videosource.h
===================================================================
--- libs/libmythtv/videosource.h	(revision 12321)
+++ libs/libmythtv/videosource.h	(working copy)
@@ -413,6 +413,37 @@
     DiSEqCDevTree      *diseqc_tree;
 };
 
+class FirewireGUID;
+class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage
+{
+    Q_OBJECT
+
+  public:
+    FirewireModel(const CaptureCard &parent, const FirewireGUID*);
+
+  public slots:
+    void SetGUID(const QString&);
+
+  private:
+    const FirewireGUID *guid;
+};
+
+class FirewireDesc : public TransLabelSetting
+{
+    Q_OBJECT
+
+  public:
+    FirewireDesc(const FirewireGUID *_guid) :
+        TransLabelSetting(), guid(_guid) { }
+
+  public slots:
+    void SetGUID(const QString&);
+
+  private:
+    const FirewireGUID *guid;
+};
+
+
 class CaptureCardGroup : public TriggeredConfigurationGroup
 {
     Q_OBJECT
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 12321)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -377,23 +377,26 @@
     }
 
     # Support for cable boxes that provide Firewire out
-    using_firewire  {
-        HEADERS += firewirechannelbase.h       firewirerecorderbase.h
-        SOURCES += firewirechannelbase.cpp     firewirerecorderbase.cpp
+    using_firewire {
+        HEADERS += firewirechannel.h           firewirerecorder.h
+        HEADERS += firewiresignalmonitor.h     firewiredevice.h
+        SOURCES += firewirechannel.cpp         firewirerecorder.cpp
+        SOURCES += firewiresignalmonitor.cpp   firewiredevice.cpp
 
         macx {
-            HEADERS += darwinfirewirechannel.h       darwinfirewirerecorder.h
-            SOURCES += darwinfirewirechannel.cpp     darwinfirewirerecorder.cpp
-            HEADERS += selectavcdevice.h
-            SOURCES += selectavcdevice.cpp
+            HEADERS += darwinfirewiredevice.h   darwinavcinfo.h
+            SOURCES += darwinfirewiredevice.cpp darwinavcinfo.cpp
+            DEFINES += USING_OSX_FIREWIRE
         }
         
         !macx {
-            HEADERS += firewirechannel.h       firewirerecorder.h
-            SOURCES += firewirechannel.cpp     firewirerecorder.cpp
+            HEADERS += linuxfirewiredevice.h
+            SOURCES += linuxfirewiredevice.cpp
+            DEFINES += USING_LINUX_FIREWIRE
         }
 
         DEFINES += USING_FIREWIRE
+        using_libavc_5_3:DEFINES += USING_LIBAVC_5_3
     }
 
     # Support for set top boxes (Nokia DBox2 etc.)
Index: libs/libmythtv/darwinfirewirerecorder.cpp
===================================================================
--- libs/libmythtv/darwinfirewirerecorder.cpp	(revision 12321)
+++ libs/libmythtv/darwinfirewirerecorder.cpp	(working copy)
@@ -1,227 +0,0 @@
-/**
- *  DarwinDarwinFirewireRecorder
- *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-// MythTV includes
-#include "darwinfirewirerecorder.h"
-#include "tspacket.h"
-
-#undef always_inline
-#include <AVCVideoServices/AVCVideoServices.h>
-
-DarwinFirewireRecorder::DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner)
- : FirewireRecorderBase(rec),
-   capture_device(
-       dynamic_cast<DarwinFirewireChannel*>(tuner)->GetAVCDevice()
-   ),
-   message_log(NULL),
-   video_stream(NULL),
-   isopen(false)
-{;}
-
-DarwinFirewireRecorder::~DarwinFirewireRecorder()
-{
-    this->Close();
-}
-
-// Various message callbacks.
-IOReturn DarwinFirewireRecorder::MPEGNoData(void *pRefCon)
-{
-    
-    DarwinFirewireRecorder* self = static_cast<DarwinFirewireRecorder*>(pRefCon);
-    self->no_data();
-    return 0;
-}
-
-void DarwinFirewireRecorder::no_data()
-{
-    VERBOSE(
-        VB_IMPORTANT, 
-        QString("Firewire: No Input in %1 seconds").arg(kTimeoutInSeconds));
-}
-
-namespace
-{
-  void avs_log_message(char *pString)
-  {
-      // I don't know what QString does with plain char*, but surely it
-      // treats char const* as an NTBS.
-      char const* s = pString;
-
-      VERBOSE(VB_GENERAL,QString("Firewire MPEG2Receiver log: %1")
-              .arg(s));
-  }
-
-  void avs_message_received(
-      UInt32 msg, UInt32 param1, UInt32 param2, void *pRefCon)
-  {
-      (void)pRefCon;
-
-      VERBOSE(VB_RECORD,QString("Firewire MPEG2Receiver message: %1")
-              .arg(msg));
-
-      switch (msg)
-      {
-      case AVS::kMpeg2ReceiverAllocateIsochPort:
-          VERBOSE(
-              VB_RECORD,
-              QString("Firewire MPEG2Receiver allocated channel: %1, speed %2")
-                  .arg(param2).arg(param1)
-          );
-          break;
-
-      case AVS::kMpeg2ReceiverDCLOverrun:
-          VERBOSE(
-              VB_IMPORTANT,
-              QString("Firewire MPEG2Receiver DCL Overrun")
-          );
-          break;
-
-      case AVS::kMpeg2ReceiverReceivedBadPacket:
-          VERBOSE(
-              VB_IMPORTANT,
-              QString("Firewire MPEG2Receiver Received Bad Packet ")
-          );
-          break;
-
-      default:
-          break;
-      }
-  }
-
-  bool find_capture_device(AVS::AVCDevice* d)
-  {
-      // We'd check isMPEGDevice, but it turns out that for the
-      // DCT-6200, Apple doesn't set that flag.  So instead we rule
-      // out DV devices.
-      // A more general OSX AVCRecorder class that also handles DV
-      // devices might not check either flag.
-      return d->isAttached && !d->isDVDevice 
-//          && (d->hasTapeSubunit || d->hasMonitorOrTunerSubunit)
-          ;
-  }
-
-  IOReturn device_controller_notification(AVS::AVCDeviceController *, void *, AVS::AVCDevice*)
-  {
-      return 0;
-  }	
-}
-
-IOReturn DarwinFirewireRecorder::tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf,void *pRefCon)
-{
-    DarwinFirewireRecorder* self = static_cast<DarwinFirewireRecorder*>(pRefCon); 
-    if (!self) 
-        return kIOReturnBadArgument;
-
-    for (UInt32 i = 0; i < tsPacketCount; ++i)
-        self->ProcessTSPacket(*(reinterpret_cast<TSPacket*>(ppBuf[i])));
-
-    return 0;
-}
-
-
-bool DarwinFirewireRecorder::Open()
-{
-     if (isopen)
-         return true;
-    
-     VERBOSE(VB_GENERAL,QString("Firewire: Creating logger object"));
-
-     this->message_log = new AVS::StringLogger(avs_log_message);
-     if (!this->message_log)
-     {
-         VERBOSE(VB_IMPORTANT, QString("Firewire: Couldn't create logger") );
-         return false;
-     }
-
-     // If we don't set this immediately, Close() will refuse to clean
-     // up after whatever mess we make here
-     this->isopen = true;
-
-     VERBOSE(VB_GENERAL,QString("Firewire: Creating MPEG-2 device stream"));
-     
-     // This not only builds an MPEG2Receiver object but also starts dedicated real-time threads.
-     this->video_stream = capture_device->CreateMPEGReceiverForDevicePlug(
-         0,                // Plug number.  Why is zero always OK?  I
-                           // don't know, but that's what Apple's
-                           // examples do.
-         tspacket_callback,
-         this,
-         avs_message_received,
-         this,
-         this->message_log,
-         AVS::kCyclesPerReceiveSegment,
-         // Why multiply by 2 instead of using the default,
-         // kNumReceiveSegments?  Because it's what Apple's only
-         // example of the use of this function does.
-         AVS::kNumReceiveSegments*2);
-         
-     if (!this->video_stream)
-     {
-         VERBOSE(VB_IMPORTANT, QString("Firewire: Couldn't create MPEG-2 device stream") );
-         this->Close();
-         return false;
-     }
-
-	// We could set the channel to receive on, but it doesn't seem
-	// like we need to, and if the device is already transmitting it
-	// could lead to inefficiency because the device stream is smart
-	// enough to avoid allocating new bandwidth.
-
-	// Register a no-data notification callback
-	video_stream->pMPEGReceiver->registerNoDataNotificationCallback(
-        MPEGNoData, this, kTimeoutInSeconds * 1000);
-
-     return true;
-}
-
-void DarwinFirewireRecorder::Close()
-{
-    if (!isopen)
-        return;
-    
-    isopen = false;
-
-    if (this->video_stream)
-    {
-        this->stop();
-        VERBOSE(VB_RECORD, "Firewire: Destroying device stream");
-        this->capture_device->DestroyAVCDeviceStream(this->video_stream);
-        this->video_stream = 0;
-    }
-
-    delete this->message_log;
-    this->message_log = 0;
-}
-
-void DarwinFirewireRecorder::start()
-{
-    VERBOSE(VB_RECORD, "Firewire: Starting video stream");
-    this->capture_device->StartAVCDeviceStream(this->video_stream);
-}
-
-void DarwinFirewireRecorder::stop()
-{
-    VERBOSE(VB_RECORD, "Firewire: Stopping video stream");
-    this->capture_device->StopAVCDeviceStream(this->video_stream);
-}
-
-bool DarwinFirewireRecorder::grab_frames()
-{
-    usleep(1000000 / 2);  // 2 times a second
-    return true;
-}        
-
-void DarwinFirewireRecorder::SetOption(const QString &name, const QString &value) 
-{
-    (void)name;
-    (void)value;
-}
-
-void DarwinFirewireRecorder::SetOption(const QString &name, int value) 
-{
-    (void)name;
-    (void)value;
-}
Index: libs/libmythtv/scanwizardhelpers.h
===================================================================
--- libs/libmythtv/scanwizardhelpers.h	(revision 12321)
+++ libs/libmythtv/scanwizardhelpers.h	(working copy)
@@ -49,6 +49,7 @@
 class AnalogPane;
 class STPane;
 class DVBUtilsImportPane;
+class QApplication;
 
 /// Max range of the ScanProgressPopup progress bar
 #define PROGRESS_MAX  1000
@@ -86,6 +87,8 @@
 
 class ScannerEvent : public QCustomEvent
 {
+    friend class QApplication; // to suppress Apple gcc warning
+
   public:
     enum TYPE 
     {
Index: libs/libmythtv/dbcheck.cpp
===================================================================
--- libs/libmythtv/dbcheck.cpp	(revision 12321)
+++ libs/libmythtv/dbcheck.cpp	(working copy)
@@ -10,7 +10,7 @@
 #include "mythdbcon.h"
 
 /// This is the DB schema version expected by the running MythTV instance.
-const QString currentDatabaseVersion = "1173";
+const QString currentDatabaseVersion = "1174";
 
 static bool UpdateDBVersionNumber(const QString &newnumber);
 static bool performActualUpdate(const QString updates[], QString version,
@@ -2782,6 +2782,16 @@
             return false;
     }
 
+    if (dbver == "1173")
+    {
+        const QString updates[] = {
+"DELETE FROM capturecard WHERE cardtype = 'FIREWIRE';",
+""
+};
+        if (!performActualUpdate(updates, "1174", dbver))
+            return false;
+    }
+
 //"ALTER TABLE cardinput DROP COLUMN preference;" in 0.22
 //"ALTER TABLE channel DROP COLUMN atscsrcid;" in 0.22
 //"ALTER TABLE recordedmarkup DROP COLUMN offset;" in 0.22
@@ -2790,6 +2800,8 @@
 //"ALTER TABLE cardinput DROP lnb_lof_switch;" in 0.22
 //"ALTER TABLE cardinput DROP lnb_lof_hi;" in 0.22
 //"ALTER TABLE cardinput DROP lnb_lof_lo;" in 0.22
+//"ALTER TABLE capturecard DROP firewire_port;" in 0.22
+//"ALTER TABLE capturecard DROP firewire_node;" in 0.22
 
     return true;
 }
Index: libs/libmythtv/signalmonitor.h
===================================================================
--- libs/libmythtv/signalmonitor.h	(revision 12321)
+++ libs/libmythtv/signalmonitor.h	(working copy)
@@ -285,6 +285,7 @@
     return (CardUtil::IsDVBCardType(cardtype) ||
             (cardtype.upper() == "HDTV")      ||
             (cardtype.upper() == "HDHOMERUN") ||
+            (cardtype.upper() == "FIREWIRE")  ||
             (cardtype.upper() == "FREEBOX"));
 }
 
Index: libs/libmythtv/darwinfirewiredevice.cpp
===================================================================
--- libs/libmythtv/darwinfirewiredevice.cpp	(revision 0)
+++ libs/libmythtv/darwinfirewiredevice.cpp	(revision 0)
@@ -0,0 +1,871 @@
+/**
+ *  DarwinFirewireChannel
+ *  Copyright (c) 2005 by Jim Westfall
+ *  SA3250HD support Copyright (c) 2005 by Matt Porter
+ *  Copyright (c) 2006 by Dave Abrahams
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// POSIX headers
+#include <pthread.h>
+
+// OS X headers
+#undef always_inline
+#include <IOKit/IOMessage.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/firewire/IOFireWireLib.h>
+#include <IOKit/firewire/IOFireWireLibIsoch.h>
+#include <IOKit/firewire/IOFireWireFamilyCommon.h>
+#include <IOKit/avc/IOFireWireAVCLib.h>
+
+// Std C++ headers
+#include <vector>
+using namespace std;
+
+// MythTV headers
+#include "darwinfirewiredevice.h"
+#include "darwinavcinfo.h"
+#include "mythcontext.h"
+
+// Apple Firewire example headers
+#include <AVCVideoServices/StringLogger.h>
+#include <AVCVideoServices/MPEG2Receiver.h>
+
+// header not used because it also requires MPEG2Transmitter.h
+//#include <AVCVideoServices/FireWireMPEG.h>
+namespace AVS
+{
+    IOReturn CreateMPEG2Receiver(
+        MPEG2Receiver           **ppReceiver,
+        DataPushProc              dataPushProcHandler,
+        void                     *pDataPushProcRefCon = nil,
+        MPEG2ReceiverMessageProc  messageProcHandler  = nil,
+        void                     *pMessageProcRefCon  = nil,
+        StringLogger             *stringLogger        = nil,
+        IOFireWireLibNubRef       nubInterface        = nil,
+        unsigned int              cyclesPerSegment    =
+            kCyclesPerReceiveSegment,
+        unsigned int              numSegments         =
+            kNumReceiveSegments,
+        bool                      doIRMAllocations    = false);
+    IOReturn DestroyMPEG2Receiver(MPEG2Receiver *pReceiver);
+}
+
+#define LOC      QString("DFireDev(): ")
+#define LOC_WARN QString("DFireDev(), Warning: ")
+#define LOC_ERR  QString("DFireDev(), Error: ")
+
+#define kAnyAvailableIsochChannel 0xFFFFFFFF
+#define kNoDataTimeout            250 /* msec */
+
+static IOReturn dfd_tspacket_handler_thunk(
+    long unsigned int tsPacketCount, UInt32 **ppBuf, void *callback_data);
+static void dfd_update_device_list(void *dfd, io_iterator_t iterator);
+static void dfd_streaming_log_message(char *pString);
+
+class DFDPriv
+{
+  public:
+    DFDPriv() :
+        controller_thread_cf_ref(NULL), controller_thread_running(false),
+        notify_port(NULL), notify_source(NULL), deviter(NULL),
+        actual_fwchan(-1), is_streaming(false), avstream(NULL), logger(NULL)
+    {
+        logger = new AVS::StringLogger(dfd_streaming_log_message);
+    }
+
+    ~DFDPriv()
+    {
+        avcinfo_list_t::iterator it = devices.begin();
+        for (; it != devices.end(); ++it)
+            delete (*it);
+        devices.clear();
+
+        if (logger)
+        {
+            delete logger;
+            logger = NULL;
+        }
+    }
+
+    pthread_t                 controller_thread;
+    CFRunLoopRef              controller_thread_cf_ref;
+    bool                      controller_thread_running;
+
+    IONotificationPortRef     notify_port;
+    CFRunLoopSourceRef        notify_source;
+    io_iterator_t             deviter;
+
+    int                       actual_fwchan;
+    bool                      is_streaming;
+    AVS::MPEG2Receiver       *avstream;
+    AVS::StringLogger        *logger;
+
+    avcinfo_list_t            devices;
+};
+
+DarwinFirewireDevice::DarwinFirewireDevice(
+    uint64_t guid, uint subunitid, uint speed) :
+    FirewireDevice(guid, subunitid, speed),
+    m_node(0), m_priv(new DFDPriv())
+{
+}
+
+DarwinFirewireDevice::~DarwinFirewireDevice()
+{
+    if (IsPortOpen())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
+        while (IsPortOpen())
+            ClosePort();
+    }
+
+    if (m_priv)
+    {
+        delete m_priv;
+        m_priv = NULL;
+    }
+}
+
+void DarwinFirewireDevice::RunController(void)
+{
+    m_priv->controller_thread_cf_ref = CFRunLoopGetCurrent();
+
+    // Set up IEEE-1394 bus change notification
+    mach_port_t master_port;
+    int ret = IOMasterPort(bootstrap_port, &master_port);
+    if (kIOReturnSuccess == ret)
+    {
+        m_priv->notify_port   = IONotificationPortCreate(master_port);
+        m_priv->notify_source = IONotificationPortGetRunLoopSource(
+            m_priv->notify_port);
+
+        CFRunLoopAddSource(m_priv->controller_thread_cf_ref,
+                           m_priv->notify_source,
+                           kCFRunLoopDefaultMode);
+
+        ret = IOServiceAddMatchingNotification(
+            m_priv->notify_port, kIOMatchedNotification,
+            IOServiceMatching("IOFireWireAVCUnit"),
+            dfd_update_device_list, this, &m_priv->deviter);
+    }
+
+    if (kIOReturnSuccess == ret)
+        dfd_update_device_list(this, m_priv->deviter);
+
+    m_priv->controller_thread_running = true;
+
+    if (kIOReturnSuccess == ret)
+        CFRunLoopRun();
+
+    QMutexLocker locker(&m_lock); // ensure that controller_thread_running seen
+
+    m_priv->controller_thread_running = false;
+}
+
+void DarwinFirewireDevice::StartController(void)
+{
+    m_lock.unlock();
+
+    pthread_create(&m_priv->controller_thread, NULL,
+                   dfd_controller_thunk, this);
+
+    m_lock.lock();
+    while (!m_priv->controller_thread_running)
+    {
+        m_lock.unlock();
+        usleep(5000);
+        m_lock.lock();
+    }
+}
+
+void DarwinFirewireDevice::StopController(void)
+{
+    if (!m_priv->controller_thread_running)
+        return;
+
+    if (m_priv->deviter)
+    {
+        IOObjectRelease(m_priv->deviter);
+        m_priv->deviter = NULL;
+    }
+    
+    if (m_priv->notify_source)
+    {
+        CFRunLoopSourceInvalidate(m_priv->notify_source);
+        m_priv->notify_source = NULL;
+    }
+
+    if (m_priv->notify_port)
+    {
+        IONotificationPortDestroy(m_priv->notify_port);
+        m_priv->notify_port = NULL;
+    }
+
+    CFRunLoopStop(m_priv->controller_thread_cf_ref);
+    
+    while (m_priv->controller_thread_running)
+    {
+        m_lock.unlock();
+        usleep(100 * 1000);
+        m_lock.lock();
+    }
+}
+
+bool DarwinFirewireDevice::OpenPort(void)
+{
+    QMutexLocker locker(&m_lock);
+
+    VERBOSE(VB_RECORD, LOC + "OpenPort()");
+
+    if (GetInfoPtr() && GetInfoPtr()->IsOpen())
+    {
+        m_open_port_cnt++;
+        return true;
+    }
+
+    StartController();
+
+    if (!m_priv->controller_thread_running)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to start firewire thread.");
+        return false;
+    }
+
+    if (!GetInfoPtr())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "No IEEE-1394 device at " +
+                QString("guid: 0x%1").arg(m_guid,0,16));
+        
+        StopController();
+        return false;
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Opening AVC Device");
+    VERBOSE(VB_RECORD, LOC + GetSubunitInfoString(GetInfoPtr()->unit_table));
+
+    if (!IsSubunitType(GetInfoPtr()->unit_table, kAVCSubunitTypeTuner) ||
+        !IsSubunitType(GetInfoPtr()->unit_table, kAVCSubunitTypePanel))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("No STB at guid: 0x%1")
+                .arg(m_guid,0,16));
+
+        StopController();
+        return false;
+    }
+
+    bool ok = GetInfoPtr()->Open(m_priv->controller_thread_cf_ref);
+    if (!ok)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for port");
+
+        return false;
+    }
+
+    // TODO we should set m_node...
+
+    m_open_port_cnt++;
+
+    return true;
+}
+
+bool DarwinFirewireDevice::ClosePort(void)
+{
+    QMutexLocker locker(&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 (GetInfoPtr() && GetInfoPtr()->IsOpen())
+    {
+        VERBOSE(VB_RECORD, LOC + "Closing AVC Device");
+
+        GetInfoPtr()->Close();
+    }
+
+    StopController();
+
+    return true;
+}
+
+bool DarwinFirewireDevice::OpenAVStream(void)
+{
+    if (IsAVStreamOpen())
+        return true;
+
+    int max_speed = GetMaxSpeed();
+    VERBOSE(VB_IMPORTANT, "Max Speed: "<<max_speed<<" Our speed: "<<m_speed);
+    m_speed = min((uint)max_speed, m_speed);
+
+    uint fwchan = 0;
+    bool streaming = IsSTBStreaming(&fwchan);
+    VERBOSE(VB_IMPORTANT, QString("STB is %1already streaming on fwchan: %2")
+            .arg(streaming?"":"not ").arg(fwchan));
+
+    // TODO we should use the stream if it already exists,
+    //      this is especially true if it is a broadcast stream...
+
+    int ret = AVS::CreateMPEG2Receiver(
+        &m_priv->avstream,
+        dfd_tspacket_handler_thunk, this,
+        dfd_stream_msg, this,
+        m_priv->logger /* StringLogger */,
+        GetInfoPtr()->fw_handle,
+        AVS::kCyclesPerReceiveSegment,
+        AVS::kNumReceiveSegments,
+        true /* p2p */);
+
+    if (kIOReturnSuccess != ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't create A/V stream object");
+        return false;
+    }
+
+    m_priv->avstream->registerNoDataNotificationCallback(
+        dfd_no_data_notification, this, kNoDataTimeout);
+
+    return true;
+}
+
+int DarwinFirewireDevice::GetMaxSpeed(void) // oMPR read
+{
+    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
+    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
+
+    FWAddress addr(0xffff, 0xf0000900, m_node);
+    uint32_t val;
+    int ret = (*fw_handle)->ReadQuadlet(
+        fw_handle, dev, &addr, (UInt32*) &val, false, 0);
+
+    return (int)((ret == kIOReturnSuccess) ? ((val>>30) & 0x3) : 0xffffffff);
+}
+
+bool DarwinFirewireDevice::IsSTBStreaming(uint *fw_channel)
+{
+    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
+    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
+
+    FWAddress addr(0xffff, 0xf0000904, m_node);
+    uint32_t val;
+    int ret = (*fw_handle)->ReadQuadlet(
+        fw_handle, dev, &addr, (UInt32*) &val, false, 0);
+
+    if (ret != kIOReturnSuccess)
+        return false;
+
+    if (val & (kIOFWPCRBroadcast | kIOFWPCRP2PCount))
+    {
+        if (fw_channel)
+            *fw_channel = (val & kIOFWPCRChannel) >> kIOFWPCRChannelPhase;
+
+        return true;
+    }
+
+    return false;
+}
+
+bool DarwinFirewireDevice::CloseAVStream(void)
+{
+    if (!m_priv->avstream)
+        return true;
+
+    StopStreaming();
+
+    VERBOSE(VB_RECORD, LOC + "Destroying A/V stream object");
+    AVS::DestroyMPEG2Receiver(m_priv->avstream);
+    m_priv->avstream = NULL;
+
+    return true;
+}
+
+bool DarwinFirewireDevice::IsAVStreamOpen(void) const
+{
+    return m_priv->avstream;
+}
+
+bool DarwinFirewireDevice::StartStreaming(void)
+{
+    if (m_priv->is_streaming)
+        return m_priv->is_streaming;
+
+    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
+
+    if (!IsAVStreamOpen() && !OpenAVStream())
+    {
+        VERBOSE(VB_IMPORTANT, LOC + "Starting A/V streaming: FAILED");
+        return false;
+    }
+
+    m_priv->avstream->setReceiveIsochChannel(kAnyAvailableIsochChannel);
+    m_priv->avstream->setReceiveIsochSpeed((IOFWSpeed) m_speed);
+    int ret = m_priv->avstream->startReceive();
+
+    m_priv->is_streaming = (kIOReturnSuccess == ret);
+
+    VERBOSE(VB_IMPORTANT, LOC + "Starting A/V streaming: "
+            <<((m_priv->is_streaming)?"success":"failure"));
+
+    return m_priv->is_streaming;
+}
+
+bool DarwinFirewireDevice::StopStreaming(void)
+{
+    if (!m_priv->is_streaming)
+        return true;
+
+    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
+
+    bool ok = (kIOReturnSuccess == m_priv->avstream->stopReceive());
+    m_priv->is_streaming = !ok;
+
+    if (!ok)
+    {
+        VERBOSE(VB_RECORD, LOC_ERR + "Failed to stop A/V streaming");
+        return false;
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
+    return true;
+}
+
+bool DarwinFirewireDevice::SendAVCCommand(const vector<uint8_t> &cmd,
+                                          vector<uint8_t>       &result,
+                                          int                   retry_cnt)
+{
+    return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
+}
+
+bool DarwinFirewireDevice::IsPortOpen(void) const
+{
+    QMutexLocker locker(&m_lock);
+
+    if (!GetInfoPtr())
+        return false;
+
+    return GetInfoPtr()->IsOpen();
+}
+
+void DarwinFirewireDevice::AddListener(TSDataListener *listener)
+{
+    FirewireDevice::AddListener(listener);
+
+    QMutexLocker locker(&m_lock);
+    if (!m_listeners.empty())
+        StartStreaming();
+}
+
+void DarwinFirewireDevice::RemoveListener(TSDataListener *listener)
+{
+    FirewireDevice::RemoveListener(listener);
+
+    QMutexLocker locker(&m_lock);
+    if (m_priv->is_streaming && m_listeners.empty())
+    {
+        StopStreaming();
+        CloseAVStream();
+    }
+}
+
+void DarwinFirewireDevice::BroadcastToListeners(
+    const unsigned char *data, uint dataSize)
+{
+    QMutexLocker locker(&m_lock);
+    FirewireDevice::BroadcastToListeners(data, dataSize);
+}
+
+void DarwinFirewireDevice::PrintNoDataMessage(void)
+{
+    VERBOSE(VB_IMPORTANT, LOC_WARN +
+            QString("No Input in %1 msecs").arg(kNoDataTimeout));
+}
+
+void DarwinFirewireDevice::ProcessStreamingMessage(
+    uint32_t msg, uint32_t param1, uint32_t param2)
+{
+    int plug_number = 0;
+
+    if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
+    {
+        int speed = param1, fw_channel = param2;
+
+        bool ok = UpdatePlugRegister(
+            plug_number, fw_channel, speed, true, false);
+
+        VERBOSE(VB_IMPORTANT, LOC + QString("AllocateIsochPort(%1,%2) %3")
+                .arg(fw_channel).arg(speed).arg(((ok)?"ok":"error")));
+    }
+    else if (AVS::kMpeg2ReceiverReleaseIsochPort == msg)
+    {
+        int ret = UpdatePlugRegister(plug_number, -1, -1, false, true);
+
+        VERBOSE(VB_IMPORTANT, LOC + "ReleaseIsochPort "
+                <<((kIOReturnSuccess == ret)?"ok":"error"));
+    }
+    else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "DCL Overrun");
+    }
+    else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Received Bad Packet");
+    }
+    else
+    {
+        VERBOSE(VB_GENERAL, LOC +
+                QString("Streaming Message: %1").arg(msg));
+    }
+}
+
+vector<AVCInfo> DarwinFirewireDevice::GetSTBList(void)
+{
+    vector<AVCInfo> list;
+
+    {
+        DarwinFirewireDevice dev(0,0,0);
+
+        dev.m_lock.lock();
+        dev.StartController();
+        dev.m_lock.unlock();
+
+        list = dev.GetSTBListPrivate();
+
+        dev.m_lock.lock();
+        dev.StopController();
+        dev.m_lock.unlock();
+    }
+
+    return list;
+}
+
+vector<AVCInfo> DarwinFirewireDevice::GetSTBListPrivate(void)
+{
+    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- begin");
+    QMutexLocker locker(&m_lock);
+    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- got lock");
+
+    vector<AVCInfo> list;
+
+    avcinfo_list_t::iterator it = m_priv->devices.begin();
+    for (; it != m_priv->devices.end(); ++it)
+    {
+        if (IsSubunitType((*it)->unit_table, kAVCSubunitTypeTuner) &&
+            IsSubunitType((*it)->unit_table, kAVCSubunitTypePanel))
+        {
+            list.push_back(*(*it));
+        }
+    }
+
+    VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- end");
+    return list;
+}
+
+void DarwinFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
+{
+    QMutexLocker locker(&m_lock);
+
+    avcinfo_list_t::iterator it = m_priv->devices.find(guid);
+
+    if (it == m_priv->devices.end())
+    {
+        DarwinAVCInfo *ptr = new DarwinAVCInfo();
+
+        VERBOSE(VB_IMPORTANT, "Adding device list item 0x"
+                <<hex<<guid<<" ptr: "<<ptr<<dec);
+
+        m_priv->devices[guid] = ptr;
+        it = m_priv->devices.find(guid);
+    }
+
+    io_object_t &item = *((io_object_t*) pitem);
+    if (it != m_priv->devices.end())
+    {
+        (*it)->Update(guid, this, m_priv->notify_port,
+                      m_priv->controller_thread_cf_ref, item);
+    }
+}
+
+DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void)
+{
+    avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
+    return (it == m_priv->devices.end()) ? NULL : *it;
+}
+
+const DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void) const
+{
+    avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
+    return (it == m_priv->devices.end()) ? NULL : *it;
+}
+
+
+bool DarwinFirewireDevice::UpdatePlugRegisterPrivate(
+    uint plug_number, int new_fw_chan, int new_speed,
+    bool add_plug, bool remove_plug)
+{
+    if (!GetInfoPtr())
+        return false;
+
+    IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
+    if (!fw_handle)
+        return false;
+
+    io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
+
+    // Read the register
+    uint      low_addr = kPCRBaseAddress + 4 + (plug_number << 2);
+    FWAddress addr(0xffff, low_addr, m_node);
+    uint32_t  old_plug_val;
+    if (kIOReturnSuccess != (*fw_handle)->ReadQuadlet(
+            fw_handle, dev, &addr, (UInt32*) &old_plug_val, false, 0))
+    {
+        return false;
+    }
+
+    int old_plug_cnt = (old_plug_val >> 24) & 0x3f;
+    int old_fw_chan  = (old_plug_val >> 16) & 0x3f;
+    int old_speed    = (old_plug_val >> 14) & 0x03;
+
+    int new_plug_cnt = (int) old_plug_cnt;
+    new_plug_cnt += ((add_plug) ? 1 : 0) - ((remove_plug) ? 1 : 0);
+    if ((new_plug_cnt > 0x3f) || (new_plug_cnt < 0))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Invalid Plug Count "<<new_plug_cnt);
+
+        return false;
+    }
+
+    new_fw_chan = (new_fw_chan >= 0) ? new_fw_chan : old_fw_chan;
+    if (old_plug_cnt && (new_fw_chan != old_fw_chan))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_WARN +
+                "Ignoring FWChan change request, plug already open");
+
+        new_fw_chan = old_fw_chan;
+    }
+
+    new_speed = (new_speed >= 0) ? new_speed : old_speed;
+    if (old_plug_cnt && (new_speed != old_speed))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_WARN +
+                "Ignoring speed change request, plug already open");
+
+        new_speed = old_speed;
+    }
+
+    uint32_t new_plug_val = old_plug_val;
+
+    new_plug_val &= ~(0x3f<<24);
+    new_plug_val &= (remove_plug) ? ~kIOFWPCRBroadcast : ~0x0;
+    new_plug_val |= (new_plug_cnt & 0x3f) << 24;
+
+    new_plug_val &= ~(0x3f<<16);
+    new_plug_val |= (new_fw_chan & 0x3F) << 16;
+
+    new_plug_val &= ~(0x03<<14);
+    new_plug_val |= (new_speed & 0x03) << 14;
+
+    return (kIOReturnSuccess == (*fw_handle)->CompareSwap(
+                fw_handle, dev, &addr, old_plug_val, new_plug_val, false, 0));
+}
+
+void DarwinFirewireDevice::HandleBusReset(void)
+{
+    int plug_number = 0;
+    if (!GetInfoPtr())
+        return;
+
+    int fw_channel = m_priv->actual_fwchan;
+    bool ok = UpdatePlugRegister(plug_number, fw_channel,
+                                 m_speed, true, false);
+    if (!ok)
+    {
+        ok = UpdatePlugRegister(plug_number, kAnyAvailableIsochChannel,
+                                m_speed, true, false);
+    }
+
+    if (!ok)
+        VERBOSE(VB_IMPORTANT, LOC + "Reset: Failed to reconnect");
+    else
+        VERBOSE(VB_RECORD, LOC + "Reset: Reconnected succesfully");
+}
+
+bool DarwinFirewireDevice::UpdatePlugRegister(
+    uint plug_number, int fw_chan, int speed,
+    bool add_plug, bool remove_plug, uint retry_cnt)
+{
+    if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
+        return false;
+
+    bool ok = false;
+
+    for (uint i = 0; (i < retry_cnt) && !ok; i++)
+    {
+        ok = UpdatePlugRegisterPrivate(
+            plug_number, fw_chan, speed, add_plug, remove_plug);
+    }
+
+    m_priv->actual_fwchan = (ok) ? fw_chan : kAnyAvailableIsochChannel;
+
+    return ok;
+}
+
+void DarwinFirewireDevice::HandleDeviceChange(uint messageType)
+{
+    QString loc = LOC + "HandleDeviceChange: ";
+
+    if (kIOMessageServiceIsTerminated == messageType)
+    {
+        VERBOSE(VB_RECORD, loc + "Disconnect");
+        // stop printing no data messages.. don't try to open
+        return;
+    }
+
+    if (kIOMessageServiceIsAttemptingOpen == messageType)
+    {
+        VERBOSE(VB_RECORD, loc + "Attempting open");
+        return;
+    }
+
+    if (kIOMessageServiceWasClosed == messageType)
+    {
+        VERBOSE(VB_RECORD, loc + "Device Closed");
+        // fill unit_table
+        return;
+    }
+
+    if (kIOMessageServiceIsSuspended == messageType)
+    {
+        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsSuspended");
+        // start of reset
+        return;
+    }
+
+    if (kIOMessageServiceIsResumed == messageType)
+    {
+        // end of reset
+        HandleBusReset();
+    }
+
+    if (kIOMessageServiceIsTerminated == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsTerminated");
+    else if (kIOMessageServiceIsRequestingClose == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsRequestingClose");
+    else if (kIOMessageServiceIsAttemptingOpen == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageServiceIsAttemptingOpen");
+    else if (kIOMessageServiceWasClosed == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageServiceWasClosed");
+    else if (kIOMessageServiceBusyStateChange == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageServiceBusyStateChange");
+    else if (kIOMessageCanDevicePowerOff == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageCanDevicePowerOff");
+    else if (kIOMessageDeviceWillPowerOff == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceWillPowerOff");
+    else if (kIOMessageDeviceWillNotPowerOff == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceWillNotPowerOff");
+    else if (kIOMessageDeviceHasPoweredOn == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageDeviceHasPoweredOn");
+    else if (kIOMessageCanSystemPowerOff == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageCanSystemPowerOff");
+    else if (kIOMessageSystemWillPowerOff == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillPowerOff");
+    else if (kIOMessageSystemWillNotPowerOff == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillNotPowerOff");
+    else if (kIOMessageCanSystemSleep == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageCanSystemSleep");
+    else if (kIOMessageSystemWillSleep == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillSleep");
+    else if (kIOMessageSystemWillNotSleep == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillNotSleep");
+    else if (kIOMessageSystemHasPoweredOn == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageSystemHasPoweredOn");
+    else if (kIOMessageSystemWillRestart == messageType)
+        VERBOSE(VB_RECORD, loc + "kIOMessageSystemWillRestart");
+    else
+    {
+        VERBOSE(VB_RECORD, loc + "unknown message 0x"
+                <<hex<<messageType<<dec);
+    }
+}
+
+// Various message callbacks.
+
+void *dfd_controller_thunk(void *param)
+{
+    ((DarwinFirewireDevice*)param)->RunController();
+    return NULL;
+}
+
+void dfd_update_device_list_item(
+    DarwinFirewireDevice *dev, uint64_t guid, void *item)
+{
+    dev->UpdateDeviceListItem(guid, item);
+}
+
+int dfd_no_data_notification(void *callback_data)
+{
+    ((DarwinFirewireDevice*)callback_data)->PrintNoDataMessage();
+
+    return kIOReturnSuccess;
+}
+
+void dfd_stream_msg(long unsigned int msg, long unsigned int param1,
+                    long unsigned int param2, void *callback_data)
+{
+    ((DarwinFirewireDevice*)callback_data)->
+        ProcessStreamingMessage(msg, param1, param2);
+}
+
+int dfd_tspacket_handler(uint tsPacketCount, uint32_t **ppBuf,
+                         void *callback_data)
+{
+    DarwinFirewireDevice *fw = (DarwinFirewireDevice*) callback_data;
+    if (!fw)
+        return kIOReturnBadArgument;
+
+    for (uint32_t i = 0; i < tsPacketCount; ++i)
+        fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 188);
+
+    return kIOReturnSuccess;
+}
+
+static IOReturn dfd_tspacket_handler_thunk(
+    long unsigned int tsPacketCount, UInt32 **ppBuf, void *callback_data)
+{
+    return dfd_tspacket_handler(
+        tsPacketCount, (uint32_t**)ppBuf, callback_data);
+}
+
+static void dfd_update_device_list(void *dfd, io_iterator_t deviter)
+{
+    DarwinFirewireDevice *dev = (DarwinFirewireDevice*) dfd;
+
+    io_object_t it = NULL;
+    while ((it = IOIteratorNext(deviter)))
+    {
+        uint64_t guid = 0;
+
+        CFMutableDictionaryRef props;
+        int ret = IORegistryEntryCreateCFProperties(
+            it, &props, kCFAllocatorDefault, kNilOptions);
+
+        if (kIOReturnSuccess == ret)
+        {
+            CFNumberRef GUIDDesc = (CFNumberRef)
+                CFDictionaryGetValue(props, CFSTR("GUID"));
+            CFNumberGetValue(GUIDDesc, kCFNumberSInt64Type, &guid);
+            CFRelease(props);
+            dfd_update_device_list_item(dev, guid, &it);
+        }
+    }
+}
+
+static void dfd_streaming_log_message(char *msg)
+{
+    VERBOSE(VB_RECORD, QString("MPEG2Receiver: %1").arg(msg));
+}
Index: libs/libmythtv/firewirerecorderbase.cpp
===================================================================
--- libs/libmythtv/firewirerecorderbase.cpp	(revision 12321)
+++ libs/libmythtv/firewirerecorderbase.cpp	(working copy)
@@ -1,163 +0,0 @@
-/**
- *  FirewireRecorder
- *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-// MythTV includes
-#include "firewirerecorderbase.h"
-#include "mythcontext.h"
-#include "mpegtables.h" 
-#include "mpegstreamdata.h"
-#include "tv_rec.h"
-
-#define LOC QString("FireRecBase: ") 
-#define LOC_ERR QString("FireRecBase, Error: ")
-
-const int FirewireRecorderBase::kTimeoutInSeconds = 15;
-
-FirewireRecorderBase::FirewireRecorderBase(TVRec *rec)
-    : DTVRecorder(rec), _mpeg_stream_data(NULL)
-{
-    SetStreamData(new MPEGStreamData(1, true));
-}
-
-FirewireRecorderBase::~FirewireRecorderBase()
-{
-    SetStreamData(NULL);
-}
-
-void FirewireRecorderBase::StartRecording(void) {
-  
-    VERBOSE(VB_RECORD, LOC + "StartRecording");
-
-    if (!Open()) {
-        _error = true;        
-        return;
-    }
-
-    _request_recording = true;
-    _recording = true;
-   
-    start();
-
-    while(_request_recording) {
-       if (PauseAndWait())
-           continue;
-
-       if (!grab_frames())
-       {
-           _error = true;
-           return;
-       }
-    }        
-    
-    stop();
-    FinishRecording();
-
-    _recording = false;
-}  
-
-void FirewireRecorderBase::ProcessTSPacket(const TSPacket &tspacket)
-{
-    if (tspacket.TransportError()) 
-        return; 
- 
-    if (tspacket.ScramplingControl()) 
-        return; 
- 
-    if (tspacket.HasAdaptationField()) 
-        StreamData()->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 == StreamData()->VideoPIDSingleProgram()) 
-        { 
-            _buffer_packets = !FindMPEG2Keyframes(&tspacket); 
-            BufferedWrite(tspacket); 
-        } 
-        else if (StreamData()->IsAudioPID(lpid)) 
-            BufferedWrite(tspacket); 
-        else if (StreamData()->IsListeningPID(lpid)) 
-            StreamData()->HandleTSTables(&tspacket); 
-        else if (StreamData()->IsWritingPID(lpid)) 
-            BufferedWrite(tspacket); 
-    } 
-  
-    _ts_stats.IncrTSPacketCount(); 
-    if (0 == _ts_stats.TSPacketCount()%1000000) 
-        VERBOSE(VB_RECORD, _ts_stats.toString());
-}
-
-void FirewireRecorderBase::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 FirewireRecorderBase::PauseAndWait(int timeout)
-{
-    if (request_pause)
-    {
-        if (!paused)
-        {
-            stop();
-            paused = true;
-            pauseWait.wakeAll();
-            if (tvrec)
-                tvrec->RecorderPaused();
-        }
-        unpauseWait.wait(timeout);
-    }
-    if (!request_pause && paused)
-    {
-        start();
-        paused = false;
-    }
-    return paused;
-}
-
-void FirewireRecorderBase::SetStreamData(MPEGStreamData *data)
-{
-    if (data == _mpeg_stream_data)
-        return;
-
-    MPEGStreamData *old_data = _mpeg_stream_data;
-    _mpeg_stream_data = data;
-
-    if (data)
-        data->AddMPEGSPListener(this);
-
-    if (old_data)
-        delete old_data;
-}
-
-void FirewireRecorderBase::HandleSingleProgramPAT(
-    ProgramAssociationTable *pat) 
-{ 
-    if (!pat) 
-        return; 
- 
-    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf; 
-    pat->tsheader()->SetContinuityCounter(next); 
-    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader()))); 
-} 
- 
-void FirewireRecorderBase::HandleSingleProgramPMT(ProgramMapTable *pmt) 
-{ 
-    if (!pmt) 
-        return; 
- 
-    int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf; 
-    pmt->tsheader()->SetContinuityCounter(next); 
-    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader()))); 
-}
Index: libs/libmythtv/firewirerecorder.cpp
===================================================================
--- libs/libmythtv/firewirerecorder.cpp	(revision 12321)
+++ libs/libmythtv/firewirerecorder.cpp	(working copy)
@@ -1,252 +1,229 @@
 /**
  *  FirewireRecorder
- *  Copyright (c) 2005 by Jim Westfall
+ *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
  *  Distributed as part of MythTV under GPL v2 and later.
  */
 
-// C includes
-#include <pthread.h>
-#include <sys/select.h>
-
-// C++ includes
-#include <iostream>
-using namespace std;
-
 // MythTV includes
 #include "firewirerecorder.h"
+#include "firewirechannel.h"
 #include "mythcontext.h"
 #include "mpegtables.h"
 #include "mpegstreamdata.h"
 #include "tv_rec.h"
 
-#define LOC QString("FireRec: ")
-#define LOC_ERR QString("FireRec, Error: ")
+#define LOC QString("FireRecBase(%1): ").arg(channel->GetDevice())
+#define LOC_ERR QString("FireRecBase(%1), Error: ").arg(channel->GetDevice())
 
-const int FirewireRecorder::kBroadcastChannel    = 63;
-const int FirewireRecorder::kConnectionP2P       = 0;
-const int FirewireRecorder::kConnectionBroadcast = 1;
-const uint FirewireRecorder::kMaxBufferedPackets = 2000;
-
-// callback function for libiec61883
-int fw_tspacket_handler(unsigned char *tspacket, int /*len*/,
-                        uint dropped, void *callback_data)
+FirewireRecorder::FirewireRecorder(TVRec *rec, FirewireChannel *chan) :
+    DTVRecorder(rec), _mpeg_stream_data(NULL),
+    channel(chan), isopen(false)
 {
-    if (dropped)
-    {
-        VERBOSE(VB_RECORD, LOC_ERR +
-                QString("Dropped %1 packet(s).").arg(dropped));
-    }
-
-    if (SYNC_BYTE != tspacket[0])
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "TS packet out of sync.");
-        return 1;
-    }
-
-    FirewireRecorder *fw = (FirewireRecorder*) callback_data;
-    if (fw)
-        fw->ProcessTSPacket(*(reinterpret_cast<TSPacket*>(tspacket)));
-
-    return (fw) ? 1 : 0;
 }
 
-static QString speed_to_string(uint speed)
+FirewireRecorder::~FirewireRecorder()
 {
-    if (speed > RAW1394_ISO_SPEED_400)
-        return QString("Invalid Speed (%1)").arg(speed);
-
-    static const uint speeds[] = { 100, 200, 400, };
-    return QString("%1Mbps").arg(speeds[speed]);
+    SetStreamData(NULL);
+    Close();
 }
 
 bool FirewireRecorder::Open(void)
 {
-     if (isopen)
-         return true;
+    if (!isopen)
+        isopen = channel->GetFirewireDevice()->OpenPort();
 
-     VERBOSE(VB_RECORD, LOC +
-             QString("Initializing Port: %1, Node: %2, Speed: %3")
-             .arg(fwport).arg(fwnode).arg(speed_to_string(fwspeed)));
+    return isopen;
+}
 
-     fwhandle = raw1394_new_handle_on_port(fwport);
-     if (!fwhandle)
-     {
-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " +
-                 QString("port: %1, bailing").arg(fwport) + ENO);
-         return false;
-     }
+void FirewireRecorder::Close(void)
+{
+    if (isopen)
+    {
+        channel->GetFirewireDevice()->ClosePort();
+        isopen = false;
+    }
+}
 
-     if (kConnectionP2P == fwconnection)
-     {
-          VERBOSE(VB_RECORD, LOC + "Creating P2P Connection " +
-                  QString("with Node: %1").arg(fwnode));
-          fwchannel = iec61883_cmp_connect(fwhandle,
-                                           fwnode | 0xffc0, &fwoplug,
-                                           raw1394_get_local_id(fwhandle),
-                                           &fwiplug, &fwbandwidth);
-          if (fwchannel > -1)
-          {
-	      VERBOSE(VB_RECORD, LOC +
-                      QString("Created Channel: %1, "
-                              "Bandwidth Allocation: %2")
-                      .arg(fwchannel).arg(fwbandwidth));
-          }
-     }
-     else
-     {
-         fwchannel = kBroadcastChannel - fwnode;
+void FirewireRecorder::StartStreaming(void)
+{
+    channel->GetFirewireDevice()->AddListener(this);
+}
 
-         VERBOSE(VB_RECORD, LOC + "Creating Broadcast Connection " +
-                 QString("with Node: %1, Channel: %2").arg(fwnode)
-                 .arg(fwchannel));
-         if (iec61883_cmp_create_bcast_output(fwhandle,
-                                              fwnode | 0xffc0, 0,
-                                              fwchannel,
-                                              fwspeed) != 0)
-         {
-             VERBOSE(VB_IMPORTANT, LOC + "Failed to create connection");
-             // release raw1394 object;
-             raw1394_destroy_handle(fwhandle);
-             return false;
-         }
-         fwbandwidth = 0;
-     }
+void FirewireRecorder::StopStreaming(void)
+{
+    channel->GetFirewireDevice()->RemoveListener(this);
+}
 
-     fwmpeg = iec61883_mpeg2_recv_init(fwhandle, fw_tspacket_handler, this);
-     if (!fwmpeg)
-     {
-         VERBOSE(VB_IMPORTANT, LOC +
-                 "Unable to init iec61883_mpeg2 object, bailing" + ENO);
+void FirewireRecorder::StartRecording(void)
+{
+    VERBOSE(VB_RECORD, LOC + "StartRecording");
 
-         // release raw1394 object;
-	 raw1394_destroy_handle(fwhandle);
-         return false;
-     }
+    if (!Open())
+    {
+        _error = true;
+        return;
+    }
 
-     // Set buffered packets size
-     size_t buffer_size = gContext->GetNumSetting("HDRingbufferSize",
-                                                  50 * TSPacket::SIZE);
-     size_t buffered_packets = min(buffer_size / 4,
-                                   (size_t) kMaxBufferedPackets);
-     iec61883_mpeg2_set_buffers(fwmpeg, buffered_packets);
-     VERBOSE(VB_IMPORTANT, LOC +
-             QString("Buffered packets %1 (%2 KB)")
-             .arg(buffered_packets).arg(buffered_packets * 4));
+    _request_recording = true;
+    _recording = true;
 
-     // Set speed if needed.
-     // Probably shouldn't even allow user to set,
-     // 100Mbps should be more the enough.
-     int curspeed = iec61883_mpeg2_get_speed(fwmpeg);
-     if (curspeed != fwspeed)
-     {
-         VERBOSE(VB_RECORD, LOC +
-                 QString("Changing Speed %1 -> %2")
-                 .arg(speed_to_string(curspeed))
-                 .arg(speed_to_string(fwspeed)));
+    StartStreaming();
 
-         iec61883_mpeg2_set_speed(fwmpeg, fwspeed);
-         if (fwspeed != iec61883_mpeg2_get_speed(fwmpeg))
-         {
-              VERBOSE(VB_IMPORTANT, LOC +
-                      "Unable to set firewire speed, continuing");
-         }
-     }
+    while (_request_recording)
+    {
+        if (!PauseAndWait())
+            usleep(50 * 1000);
+    }
 
-     fwfd = raw1394_get_fd(fwhandle);
+    StopStreaming();
+    FinishRecording();
 
-     return isopen = true;
+    _recording = false;
 }
 
-void FirewireRecorder::Close(void)
+void FirewireRecorder::AddData(const unsigned char *data, uint len)
 {
-    if (!isopen)
+    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;
+    }
 
-    isopen = false;
+    buffer.insert(buffer.end(), data, data + len);
+    bufsz += len;
 
-    VERBOSE(VB_RECORD, LOC + "Releasing iec61883_mpeg2 object");
-    iec61883_mpeg2_close(fwmpeg);
+    int sync_at = -1;
+    for (uint i = 0; (i < bufsz) && (sync_at < 0); i++)
+    {
+        if (buffer[i] == SYNC_BYTE)
+            sync_at = i;
+    }
 
-    if (fwconnection == kConnectionP2P && fwchannel > -1)
+    if (sync_at < 0)
+        return;
+
+    if (bufsz < 30 * TSPacket::SIZE)
+        return; // build up a little buffer
+
+    while (sync_at + TSPacket::SIZE < bufsz)
     {
-        VERBOSE(VB_RECORD, LOC +
-                QString("Disconnecting channel %1").arg(fwchannel));
+        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(
+                              &buffer[0] + sync_at)));
 
-        iec61883_cmp_disconnect(fwhandle, fwnode | 0xffc0, fwoplug,
-                                raw1394_get_local_id (fwhandle),
-                                fwiplug, fwchannel, fwbandwidth);
+        sync_at += TSPacket::SIZE;
     }
 
-    VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle");
-    raw1394_destroy_handle(fwhandle);
+    buffer.erase(buffer.begin(), buffer.begin() + sync_at);
+
+    return;
 }
 
-bool FirewireRecorder::grab_frames()
+void FirewireRecorder::ProcessTSPacket(const TSPacket &tspacket)
 {
-    struct timeval tv;
-    fd_set rfds;
+    if (tspacket.TransportError())
+        return;
 
-    FD_ZERO(&rfds); 
-    FD_SET(fwfd, &rfds); 
-    tv.tv_sec = kTimeoutInSeconds; 
-    tv.tv_usec = 0;
+    if (tspacket.ScramplingControl())
+        return;
 
-    if (select(fwfd + 1, &rfds, NULL, NULL, &tv)  <= 0) 
-    { 
-        VERBOSE(VB_IMPORTANT, LOC + 
-                QString("No Input in %1 seconds [P:%2 N:%3] (select)") 
-                .arg(kTimeoutInSeconds).arg(fwport).arg(fwnode)); 
-        return false; 
-    }
+    if (tspacket.HasAdaptationField())
+        GetStreamData()->HandleAdaptationFieldControl(&tspacket);
 
-    int ret = raw1394_loop_iterate(fwhandle); 
-    if (ret)
+    if (tspacket.HasPayload())
     {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " + 
-                QString("returned %1").arg(ret)); 
-        return false;
-    }
+        const unsigned int lpid = tspacket.PID();
 
-    return true;
+        // Pass or reject packets based on PID, and parse info from them
+        if (lpid == GetStreamData()->VideoPIDSingleProgram())
+        {
+            _buffer_packets = !FindMPEG2Keyframes(&tspacket);
+            BufferedWrite(tspacket);
+        }
+        else if (GetStreamData()->IsAudioPID(lpid))
+            BufferedWrite(tspacket);
+        else if (GetStreamData()->IsListeningPID(lpid))
+            GetStreamData()->HandleTSTables(&tspacket);
+        else if (GetStreamData()->IsWritingPID(lpid))
+            BufferedWrite(tspacket);
+    }
 }
 
-void FirewireRecorder::SetOption(const QString &name, const QString &value)
+void FirewireRecorder::SetOptionsFromProfile(RecordingProfile *profile,
+                                                 const QString &videodev,
+                                                 const QString &audiodev,
+                                                 const QString &vbidev)
 {
-    if (name == "model")
-        fwmodel = value;
+    (void)videodev;
+    (void)audiodev;
+    (void)vbidev;
+    (void)profile;
 }
 
-void FirewireRecorder::SetOption(const QString &name, int value)
+// documented in recorderbase.cpp
+bool FirewireRecorder::PauseAndWait(int timeout)
 {
-    if (name == "port")
-	fwport = value;
-    else if (name == "node")
-        fwnode = value;
-    else if (name == "speed")
+    if (request_pause)
     {
-        if (RAW1394_ISO_SPEED_100 != value &&
-            RAW1394_ISO_SPEED_200 != value &&
-            RAW1394_ISO_SPEED_400 != value)
+        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause");
+        if (!paused)
         {
-            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    QString("Unknown speed '%1', will use 100Mbps")
-                    .arg(value));
-
-            value = RAW1394_ISO_SPEED_100;
+            StopStreaming();
+            paused = true;
+            pauseWait.wakeAll();
+            if (tvrec)
+                tvrec->RecorderPaused();
         }
-        fwspeed = value;
+        unpauseWait.wait(timeout);
     }
-    else if (name == "connection")
+    if (!request_pause && paused)
     {
-	if (kConnectionP2P       != value &&
-            kConnectionBroadcast != value)
-        {
-	    VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    QString("Unknown connection type '%1', will use P2P")
-                    .arg(fwconnection));
+        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause");
+        StartStreaming();
+        paused = false;
+    }
+    return paused;
+}
 
-            fwconnection = kConnectionP2P;
-        }
-	fwconnection = value;
+void FirewireRecorder::SetStreamData(MPEGStreamData *data)
+{
+    if (data == _mpeg_stream_data)
+        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());
     }
 }
+
+void FirewireRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
+{
+    if (!pat)
+        return;
+
+    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
+    pat->tsheader()->SetContinuityCounter(next);
+    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));
+}
+
+void FirewireRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
+{
+    if (!pmt)
+        return;
+
+    int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
+    pmt->tsheader()->SetContinuityCounter(next);
+    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));
+}
Index: libs/libmythtv/firewirerecorder.h
===================================================================
--- libs/libmythtv/firewirerecorder.h	(revision 12321)
+++ libs/libmythtv/firewirerecorder.h	(working copy)
@@ -4,64 +4,69 @@
  *  Distributed as part of MythTV under GPL v2 and later.
  */
 
-#ifndef FIREWIRERECORDER_H_
-#define FIREWIRERECORDER_H_
+#ifndef _FIREWIRERECORDER_H_
+#define _FIREWIRERECORDER_H_
 
-#include "firewirerecorderbase.h"
-#include "tsstats.h"
-#include <libraw1394/raw1394.h>
-#include <libiec61883/iec61883.h>
+// MythTV headers
+#include "dtvrecorder.h"
+#include "tspacket.h"
+#include "streamlisteners.h"
 
+class TVRec;
+class FirewireChannel;
+
 /** \class FirewireRecorder
- *  \brief Linux FirewireRFecorder
+ *  \brief This is a specialization of DTVRecorder used to
+ *         handle DVB and ATSC streams from a firewire input.
  *
- *  \sa FirewireRecorderBase
+ *  \sa DTVRecorder
  */
-class FirewireRecorder : public FirewireRecorderBase
+class FirewireRecorder : public DTVRecorder,
+                         public MPEGSingleProgramStreamListener,
+                         public TSDataListener
 {
-    friend int fw_tspacket_handler(unsigned char*,int,uint,void*);
+    friend class MPEGStreamData;
+    friend class TSPacketProcessor;
 
   public:
-    FirewireRecorder(TVRec *rec) 
-        : FirewireRecorderBase(rec),
-        fwport(-1),     fwchannel(-1), fwspeed(-1),   fwbandwidth(-1), 
-        fwfd(-1),       fwconnection(kConnectionP2P), 
-        fwoplug(-1),    fwiplug(-1),   fwmodel(""),   fwnode(0), 
-        fwhandle(NULL), fwmpeg(NULL),  isopen(false) { } 
-   ~FirewireRecorder() { Close(); }
+    FirewireRecorder(TVRec *rec, FirewireChannel *chan);
+    virtual ~FirewireRecorder();
 
     // Commands
-    bool Open(void); 
+    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 SetOption(const QString &name, const QString &value);
-    void SetOption(const QString &name, int value);
+    void SetOptionsFromProfile(RecordingProfile *profile,
+                               const QString &videodev,
+                               const QString &audiodev,
+                               const QString &vbidev);
+    void SetStreamData(MPEGStreamData*);
 
-  private:
-    void Close(void);
-    void start() { iec61883_mpeg2_recv_start(fwmpeg, fwchannel); } 
-    void stop() { iec61883_mpeg2_recv_stop(fwmpeg); } 
-    bool grab_frames();
+    // Gets
+    MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; }
 
+    // MPEG Single Program
+    void HandleSingleProgramPAT(ProgramAssociationTable*);
+    void HandleSingleProgramPMT(ProgramMapTable*);
+
+  protected:
+    FirewireRecorder(TVRec *rec);
+
   private:
-    int              fwport;
-    int              fwchannel;
-    int              fwspeed;
-    int              fwbandwidth;
-    int              fwfd;
-    int              fwconnection;
-    int              fwoplug;
-    int              fwiplug;
-    QString          fwmodel;
-    nodeid_t         fwnode;
-    raw1394handle_t  fwhandle;
-    iec61883_mpeg2_t fwmpeg;
-    bool             isopen;
-
-    static const int kBroadcastChannel;
-    static const int kConnectionP2P;
-    static const int kConnectionBroadcast;
-    static const uint kMaxBufferedPackets;
+    MPEGStreamData        *_mpeg_stream_data;
+    FirewireChannel       *channel;
+    bool                   isopen;
+    vector<unsigned char>  buffer;
 };
 
-#endif
+#endif //  _FIREWIRERECORDER_H_
Index: libs/libmythtv/darwinavcinfo.cpp
===================================================================
--- libs/libmythtv/darwinavcinfo.cpp	(revision 0)
+++ libs/libmythtv/darwinavcinfo.cpp	(revision 0)
@@ -0,0 +1,340 @@
+/**
+ *  DarwinFirewireChannel
+ *  Copyright (c) 2006 by Daniel Kristjansson
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// Std C++ headers
+#include <vector>
+using namespace std;
+
+// MythTV headers
+#include "darwinfirewiredevice.h"
+#include "darwinavcinfo.h"
+#include "mythcontext.h"
+
+#ifndef kIOFireWireAVCLibUnitInterfaceID2
+#define kIOFireWireAVCLibUnitInterfaceID2 \
+    CFUUIDGetConstantUUIDWithBytes( \
+        NULL, \
+        0x85, 0xB5, 0xE9, 0x54, 0x0A, 0xEF, 0x11, 0xD8, \
+        0x8D, 0x19, 0x00, 0x03, 0x93, 0x91, 0x4A, 0xBA)
+#endif
+
+static void dfd_device_change_msg(
+    void*, io_service_t, natural_t messageType, void*);
+
+void DarwinAVCInfo::Update(uint64_t _guid, DarwinFirewireDevice *dev,
+                           IONotificationPortRef notify_port,
+                           CFRunLoopRef &thread_cf_ref, io_object_t obj)
+{
+    IOObjectRelease(fw_device_notifier_ref);
+    IOObjectRelease(fw_node_ref);
+    IOObjectRelease(fw_device_ref);
+    IOObjectRelease(fw_service_ref);
+    IOObjectRelease(avc_service_ref);
+
+    avc_service_ref = obj;
+
+    IORegistryEntryGetParentEntry(
+        avc_service_ref, kIOServicePlane, &fw_service_ref);
+    IORegistryEntryGetParentEntry(
+        fw_service_ref,  kIOServicePlane, &fw_device_ref);
+    IORegistryEntryGetParentEntry(
+        fw_device_ref,   kIOServicePlane, &fw_node_ref);
+
+    if (notify_port)
+    {
+        IOServiceAddInterestNotification(
+            notify_port, obj, kIOGeneralInterest,
+            dfd_device_change_msg, dev,
+            &fw_device_notifier_ref);
+    }
+
+    if (guid == _guid)
+        return; // we're done
+
+    guid = _guid;
+
+    //////////////////////////
+    // get basic info
+
+    CFMutableDictionaryRef props;
+    int ret = IORegistryEntryCreateCFProperties(
+        obj, &props, kCFAllocatorDefault, kNilOptions);
+    if (kIOReturnSuccess != ret)
+        return; // this is bad
+
+    CFNumberRef specDesc = (CFNumberRef)
+        CFDictionaryGetValue(props, CFSTR("Unit_Spec_ID"));
+    CFNumberGetValue(specDesc, kCFNumberSInt32Type, &specid);
+
+    CFNumberRef typeDesc = (CFNumberRef)
+        CFDictionaryGetValue(props, CFSTR("Unit_Type"));
+    CFNumberGetValue(typeDesc, kCFNumberSInt32Type, &modelid);
+
+    CFNumberRef vendorDesc = (CFNumberRef)
+        CFDictionaryGetValue(props, CFSTR("Vendor_ID"));
+    CFNumberGetValue(vendorDesc, kCFNumberSInt32Type, &vendorid);
+
+    CFNumberRef versionDesc = (CFNumberRef)
+        CFDictionaryGetValue(props, CFSTR("Unit_SW_Version"));
+    CFNumberGetValue(versionDesc, kCFNumberSInt32Type, &firmware_revision);
+
+    CFStringRef tmp0 = (CFStringRef)
+        CFDictionaryGetValue(props, CFSTR("FireWire Product Name"));
+    if (tmp0)
+    {
+        char tmp1[1024];
+        bzero(tmp1, sizeof(tmp1));
+        CFStringGetCString(tmp0, tmp1, sizeof(tmp1) - sizeof(char),
+                           kCFStringEncodingMacRoman);
+        product_name = QString("%1").arg(tmp1);
+    }
+
+    CFRelease(props);
+
+    //////////////////////////
+    // get subunit info
+
+    VERBOSE(VB_RECORD, "Scanning guid: 0x"<<hex<<guid<<dec);
+
+    bool wasOpen = IsAVCInterfaceOpen();
+    if (OpenAVCInterface(thread_cf_ref))
+    {
+        memset(unit_table, 0xff, 32 * sizeof(uint8_t));
+
+        for (uint i = 0; i < 8; i++)
+        {
+            vector<uint8_t> cmd;
+            vector<uint8_t> ret;
+
+            cmd.push_back(FirewireDevice::kAVCStatusInquiryCommand);
+            cmd.push_back(FirewireDevice::kAVCSubunitTypeUnit |
+                          FirewireDevice::kAVCSubunitIdIgnore);
+            cmd.push_back(FirewireDevice::kAVCUnitSubunitInfoOpcode);
+            cmd.push_back((i<<4) | 0x07);
+            cmd.push_back(0xFF);
+            cmd.push_back(0xFF);
+            cmd.push_back(0xFF);
+            cmd.push_back(0xFF);
+
+            if (!SendAVCCommand(cmd, ret, -1))
+            {
+                VERBOSE(VB_IMPORTANT, "SendAVCCommand failed");
+                continue;
+            }
+
+            if (ret.size() >= 8)
+            {
+                unit_table[(i<<2)+0] = ret[4];
+                unit_table[(i<<2)+1] = ret[5];
+                unit_table[(i<<2)+2] = ret[6];
+                unit_table[(i<<2)+3] = ret[7];
+
+                VERBOSE(VB_RECORD, "Added subunits:"<<hex
+                        <<" 0x"<<((int)ret[4])<<" 0x"<<((int)ret[5])
+                        <<" 0x"<<((int)ret[6])<<" 0x"<<((int)ret[7])
+                        <<" filt:"
+                        <<" 0x"<<(ret[4] & FirewireDevice::kAVCSubunitTypeUnit)
+                        <<" 0x"<<(ret[5] & FirewireDevice::kAVCSubunitTypeUnit)
+                        <<" 0x"<<(ret[6] & FirewireDevice::kAVCSubunitTypeUnit)
+                        <<" 0x"<<(ret[7] & FirewireDevice::kAVCSubunitTypeUnit)
+                        <<dec);
+            }
+        }
+
+        if (!wasOpen)
+            CloseAVCInterface();
+    }
+}
+
+bool DarwinAVCInfo::SendAVCCommand(
+    const vector<uint8_t> &cmd,
+    vector<uint8_t>       &result,
+    int                   /*retry_cnt*/)
+{
+    result.clear();
+
+    uint32_t result_length = 4096;
+    uint8_t response[4096];
+
+    if (!avc_handle)
+        return false;
+
+    int ret = (*avc_handle)->
+        AVCCommand(avc_handle, (const UInt8*) &cmd[0], cmd.size(),
+                   response, (UInt32*) &result_length);
+
+    if (ret != kIOReturnSuccess)
+        return false;
+
+    if (result_length)
+        result.insert(result.end(), response, response + result_length);
+
+    return true;
+}
+
+bool DarwinAVCInfo::Open(CFRunLoopRef &thread_cf_ref)
+{
+    if (IsOpen())
+        return true;
+
+    if (!OpenAVCInterface(thread_cf_ref))
+        return false;
+
+    if (!OpenDeviceInterface(thread_cf_ref))
+    {
+        CloseAVCInterface();
+        return false;
+    }
+
+    return true;
+}
+
+void DarwinAVCInfo::Close(void)
+{
+    CloseDeviceInterface();
+    CloseAVCInterface();
+}
+
+bool DarwinAVCInfo::OpenAVCInterface(CFRunLoopRef &thread_cf_ref)
+{
+    if (IsAVCInterfaceOpen())
+        return true;
+
+    if (!avc_service_ref)
+        return false;
+
+    IOCFPlugInInterface **input_plug;
+    int32_t dummy;
+    int ret = IOCreatePlugInInterfaceForService(
+        avc_service_ref, kIOFireWireAVCLibUnitTypeID, kIOCFPlugInInterfaceID,
+        &input_plug, (SInt32*) &dummy);
+
+    if (kIOReturnSuccess != ret)
+        return false;
+
+    // Try to get post-Jaguar interface
+    HRESULT err = (*input_plug)->QueryInterface(
+            input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID2),
+            (void**) &avc_handle);
+
+    // On failure, try Jaguar interface
+    if (S_OK != err)
+    {
+        err = (*input_plug)->QueryInterface(
+            input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID),
+            (void**) &avc_handle);
+    }
+
+    if (S_OK != err)
+    {
+        (*input_plug)->Release(input_plug);
+        return false;
+    }
+
+    // Add avc_handle to the event loop
+    ret = (*avc_handle)->addCallbackDispatcherToRunLoop(
+        avc_handle, thread_cf_ref);
+
+    (*input_plug)->Release(input_plug);
+
+    if (kIOReturnSuccess != ret)
+    {
+        (*avc_handle)->Release(avc_handle);
+        avc_handle = NULL;
+        return false;
+    }
+
+    ret = (*avc_handle)->open(avc_handle);
+    if (kIOReturnSuccess != ret)
+    {
+        (*avc_handle)->Release(avc_handle);
+        avc_handle = NULL;
+        return false;
+    }
+
+    return true;
+}
+
+void DarwinAVCInfo::CloseAVCInterface(void)
+{
+    if (!avc_handle)
+        return;
+
+    (*avc_handle)->removeCallbackDispatcherFromRunLoop(avc_handle);
+    (*avc_handle)->close(avc_handle);
+    (*avc_handle)->Release(avc_handle);
+
+    avc_handle = NULL;
+}
+
+bool DarwinAVCInfo::OpenDeviceInterface(CFRunLoopRef &thread_cf_ref)
+{
+    if (fw_handle)
+        return true;
+
+    if (!avc_handle)
+        return false;
+
+    IOCFPlugInInterface **input_plug;
+    int32_t dummy;
+    int ret = IOCreatePlugInInterfaceForService(
+        fw_device_ref, kIOFireWireLibTypeID, kIOCFPlugInInterfaceID,
+        &input_plug, (SInt32*) &dummy);
+
+    if (kIOReturnSuccess != ret)
+        return false;
+
+    HRESULT err = (*input_plug)->QueryInterface(
+        input_plug, CFUUIDGetUUIDBytes(kIOFireWireNubInterfaceID),
+        (void**) &fw_handle);
+
+    if (S_OK != err)
+    {
+        (*input_plug)->Release(input_plug);
+        return false;
+    }
+
+    // Add fw_handle to the event loop
+    ret = (*fw_handle)->AddCallbackDispatcherToRunLoop(
+        fw_handle, thread_cf_ref);
+
+    (*input_plug)->Release(input_plug);
+
+    if (kIOReturnSuccess == ret)
+    {
+        // open the interface
+        ret = (*fw_handle)->OpenWithSessionRef(
+            fw_handle, (*avc_handle)->getSessionRef(avc_handle));
+    }
+
+    if (kIOReturnSuccess != ret)
+    {
+        (*fw_handle)->Release(fw_handle);
+        fw_handle = NULL;
+        return false;
+    }
+
+    return true;
+}
+
+void DarwinAVCInfo::CloseDeviceInterface(void)
+{
+    if (!fw_handle)
+        return;
+
+    (*fw_handle)->RemoveCallbackDispatcherFromRunLoop(fw_handle);
+    (*fw_handle)->Close(fw_handle);
+    (*fw_handle)->Release(fw_handle);
+
+    fw_handle = NULL;
+}
+
+static void dfd_device_change_msg(
+    void *dfd, io_service_t, natural_t messageType, void*)
+{
+    DarwinFirewireDevice *dev = (DarwinFirewireDevice*) dfd;
+    dev->HandleDeviceChange(messageType);
+}
Index: libs/libmythtv/darwinfirewiredevice.h
===================================================================
--- libs/libmythtv/darwinfirewiredevice.h	(revision 0)
+++ libs/libmythtv/darwinfirewiredevice.h	(revision 0)
@@ -0,0 +1,83 @@
+#ifndef _DARWIN_FIREWIRE_DEVICE_H_
+#define _DARWIN_FIREWIRE_DEVICE_H_
+
+#include "firewiredevice.h"
+
+class DFDPriv;
+class DarwinAVCInfo;
+
+class DarwinFirewireDevice : public FirewireDevice
+{
+    friend void *dfd_controller_thunk(void *param);
+    friend void dfd_update_device_list_item(DarwinFirewireDevice *dev,
+                                       uint64_t guid, void *item);
+    friend int dfd_no_data_notification(void *cb_data);
+    friend void dfd_stream_msg(
+        long unsigned int msg, long unsigned int param1,
+        long unsigned int param2, void *callback_data);
+    friend int dfd_tspacket_handler(
+        uint tsPacketCount, uint32_t **ppBuf, void *callback_data);
+
+
+  public:
+    DarwinFirewireDevice(uint64_t guid, uint subunitid, uint speed);
+    ~DarwinFirewireDevice();
+
+    virtual bool OpenPort(void);
+    virtual bool ClosePort(void);
+    void HandleDeviceChange(uint messageType);
+
+    virtual void AddListener(TSDataListener*);
+    virtual void RemoveListener(TSDataListener*);
+
+    // Gets
+    virtual bool IsPortOpen(void) const;
+
+    // Statics
+    static vector<AVCInfo> GetSTBList(void);
+
+  private:
+    void StartController(void);
+    void StopController(void);
+
+    bool OpenAVStream(void);
+    bool CloseAVStream(void);
+    bool IsAVStreamOpen(void) const;
+
+    bool StartStreaming(void);
+    bool StopStreaming(void);
+
+    virtual bool SendAVCCommand(
+        const vector<uint8_t> &cmd,
+        vector<uint8_t>       &result,
+        int                   /*retry_cnt*/);
+
+    void HandleBusReset(void);
+    bool UpdatePlugRegisterPrivate(
+        uint plug_number, int fw_chan, int new_speed,
+        bool add_plug, bool remove_plug);
+    bool UpdatePlugRegister(
+        uint plug_number, int fw_chan, int speed,
+        bool add_plug, bool remove_plug, uint retry_cnt = 4);
+
+    void RunController(void);
+    void BroadcastToListeners(const unsigned char *data, uint dataSize);
+    void UpdateDeviceListItem(uint64_t guid, void *item);
+    void PrintNoDataMessage(void);
+    void ProcessStreamingMessage(
+        uint32_t msg, uint32_t param1, uint32_t param2);
+
+    DarwinAVCInfo *GetInfoPtr(void);
+    const DarwinAVCInfo *GetInfoPtr(void) const;
+
+    int GetMaxSpeed(void);
+    bool IsSTBStreaming(uint *fw_channel = NULL);
+
+    vector<AVCInfo> GetSTBListPrivate(void);
+
+  private:
+    uint     m_node;
+    DFDPriv *m_priv;
+};
+
+#endif // _DARWIN_FIREWIRE_DEVICE_H_
Index: libs/libmythtv/darwinfirewirechannel.cpp
===================================================================
--- libs/libmythtv/darwinfirewirechannel.cpp	(revision 12321)
+++ libs/libmythtv/darwinfirewirechannel.cpp	(working copy)
@@ -1,110 +0,0 @@
-/**
- *  DarwinFirewireChannel
- *  Copyright (c) 2005 by Jim Westfall
- *  SA3250HD support Copyright (c) 2005 by Matt Porter
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-
-#include <iostream>
-#include "mythcontext.h"
-#include "darwinfirewirechannel.h"
-
-#include "selectavcdevice.h"
-
-#undef always_inline
-#include <AVCVideoServices/AVCVideoServices.h>
-
-
-namespace
-{
-  bool find_device(AVS::AVCDevice* d)
-  {
-      return d->isAttached && d->hasMonitorOrTunerSubunit
-          // For the time being, the DarwinFireWireRecorder doesn't
-          // handle DVB devices, so there's no point in finding one we
-          // can tune to, here.  That saves us from having to search
-          // twice for an eligible device.
-          && !d->isDVDevice  
-          ;
-  }
-}
-
-DarwinFirewireChannel::DarwinFirewireChannel(FireWireDBOptions const& firewire_opts,TVRec *parent)
-  : FirewireChannelBase(parent)
-  , device_controller(0)
-  , device(0)
-{
-    (void)firewire_opts;
-}
-
-bool DarwinFirewireChannel::OpenFirewire()
-{
-    IOReturn err = AVS::CreateAVCDeviceController(&this->device_controller);
-    if (err)
-    {
-        VERBOSE(
-            VB_IMPORTANT, 
-                QString("unable to open device controller: %1").arg(err,0,16));
-        return false;
-    }
-
-    if ((this->device = SelectAVCDevice(device_controller, find_device)))
-    {
-        VERBOSE(VB_RECORD, QString("DarwinFirewireChannel: opening device") );
-        err = this->device->openDevice();
-        if (!err)
-            return true;
-
-        VERBOSE(
-            VB_IMPORTANT,
-            QString("FireWireChannel: couldn't open tuner device: %1").arg(err,0,16));
-    }
-    else
-    {
-        VERBOSE(
-            VB_IMPORTANT,
-            QString(
-                "DarwinFireWireChannel: unable to find an attached"
-                " MPEG2 device that supports channel changes"));
-    }
-    AVS::DestroyAVCDeviceController(this->device_controller);
-    return false;
-}
-
-void DarwinFirewireChannel::CloseFirewire()
-{
-    this->device->closeDevice();
-    AVS::DestroyAVCDeviceController(this->device_controller);
-    // Leave the device controller for the destructor
-}
-
-AVS::AVCDevice* DarwinFirewireChannel::GetAVCDevice() const
-{
-    return this->device;
-}
-
-bool DarwinFirewireChannel::SetChannelByNumber(int channel)
-{
-     // If the tuner is off, try to turn it on.
-     UInt8 power_state;
-     IOReturn err = this->device->GetPowerState(&power_state);
-     if (err == kIOReturnSuccess && power_state == kAVCPowerStateOff)
-     {
-         this->device->SetPowerState(kAVCPowerStateOn);
-        
-         // Give it time to power up.
-         usleep(2000000); // Sleep for two seconds
-     }
-
-     AVS::PanelSubunitController panel(this->device);
-     err = panel.Tune(channel);
-     if (err != kIOReturnSuccess)
-     {
-         VERBOSE(VB_GENERAL, QString("DarwinFirewireChannel: Tuning failed: %1").arg(err,0,16));
-         VERBOSE(VB_GENERAL, QString("Ignoring error per apple example"));
-     }
-     // Give it time to transition.        
-     usleep(1000000); // Sleep for one second
-     return true;
-}
Index: libs/libmythtv/firewiresignalmonitor.cpp
===================================================================
--- libs/libmythtv/firewiresignalmonitor.cpp	(revision 0)
+++ libs/libmythtv/firewiresignalmonitor.cpp	(revision 0)
@@ -0,0 +1,294 @@
+// -*- 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 "firewirechannel.h"
+#include "firewiresignalmonitor.h"
+
+#define LOC QString("FireSM(%1): ").arg(channel->GetDevice())
+#define LOC_WARN QString("FireSM(%1), Warning: ").arg(channel->GetDevice())
+#define LOC_ERR QString("FireSM(%1), Error: ").arg(channel->GetDevice())
+
+const uint FirewireSignalMonitor::kPowerTimeout  = 3000; /* ms */
+const uint FirewireSignalMonitor::kBufferTimeout = 5000; /* ms */
+
+QMap<void*,uint> FirewireSignalMonitor::pat_keys;
+QMutex           FirewireSignalMonitor::pat_keys_lock;
+
+/** \fn FirewireSignalMonitor::FirewireSignalMonitor(int,FirewireChannel*,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 FirewireChannel for card
+ *  \param _flags   Flags to start with
+ *  \param _name    Name for Qt signal debugging
+ */
+FirewireSignalMonitor::FirewireSignalMonitor(
+    int db_cardnum,
+    FirewireChannel *_channel,
+    uint _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 =
+        (FirewireDevice::kAVCPowerOff == _channel->GetPowerState());
+}
+
+/** \fn FirewireSignalMonitor::~FirewireSignalMonitor()
+ *  \brief Stops signal monitoring and table monitoring threads.
+ */
+FirewireSignalMonitor::~FirewireSignalMonitor()
+{
+    VERBOSE(VB_CHANNEL, LOC + "dtor");
+    Stop();
+}
+
+void FirewireSignalMonitor::deleteLater(void)
+{
+    disconnect(); // disconnect signals we may be sending...
+    Stop();
+    DTVSignalMonitor::deleteLater();
+}
+
+/** \fn FirewireSignalMonitor::Stop(void)
+ *  \brief Stop signal monitoring and table monitoring threads.
+ */
+void FirewireSignalMonitor::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 FirewireSignalMonitor::HandlePAT(const ProgramAssociationTable *pat)
+{
+    AddFlags(kDTVSigMon_PATSeen);
+
+    FirewireChannel *fwchan = dynamic_cast<FirewireChannel*>(channel);
+    bool crc_bogus = !fwchan->GetFirewireDevice()->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 FirewireSignalMonitor::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 *FirewireSignalMonitor::TableMonitorThread(void *param)
+{
+    FirewireSignalMonitor *mon = (FirewireSignalMonitor*) param;
+    mon->RunTableMonitor();
+    return NULL;
+}
+
+void FirewireSignalMonitor::RunTableMonitor(void)
+{
+    stb_needs_to_wait_for_pat = true;
+    stb_wait_for_pat_timer.start();
+    dtvMonitorRunning = true;
+
+    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin");
+
+    FirewireChannel *lchan = dynamic_cast<FirewireChannel*>(channel);
+    if (!lchan)
+    {
+        VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end");
+        dtvMonitorRunning = false;
+        return;
+    }
+
+    FirewireDevice *dev = lchan->GetFirewireDevice();
+
+    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 FirewireSignalMonitor::AddData(const unsigned char *data, uint len)
+{
+    if (!dtvMonitorRunning)
+        return;
+
+    if (GetStreamData())
+        GetStreamData()->ProcessData((unsigned char *)data, len);
+}
+
+/** \fn FirewireSignalMonitor::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 FirewireSignalMonitor::UpdateValues(void)
+{
+    if (!running || exit)
+        return;
+
+    if (dtvMonitorRunning)
+    {
+        EmitFirewireSignals();
+        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;
+
+    FirewireChannel *fwchan = dynamic_cast<FirewireChannel*>(channel);
+
+    if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch))
+    {
+        FirewireDevice::PowerState power = fwchan->GetPowerState();
+        if (FirewireDevice::kAVCPowerOn == power)
+        {
+            AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
+        }
+        else if (FirewireDevice::kAVCPowerOff == power)
+        {
+            AddFlags(kFWSigMon_PowerSeen);
+            fwchan->SetPowerState(true);
+            stb_wait_for_power_timer.start();
+            stb_needs_to_wait_for_power = true;
+        }
+    }
+
+    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);
+    }
+
+    EmitFirewireSignals();
+    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 FirewireSignalMonitor::EmitFirewireSignals(void)
+ *  \brief Emits signals for lock, signal strength, etc.
+ */
+void FirewireSignalMonitor::EmitFirewireSignals(void)
+{
+    // Emit signals..
+    EMIT(StatusSignalLock, signalLock); 
+    if (HasFlags(kDTVSigMon_WaitForSig))
+        EMIT(StatusSignalStrength, signalStrength);
+}
+
+#undef EMIT
Index: libs/libmythtv/darwinavcinfo.h
===================================================================
--- libs/libmythtv/darwinavcinfo.h	(revision 0)
+++ libs/libmythtv/darwinavcinfo.h	(revision 0)
@@ -0,0 +1,75 @@
+#ifndef _DARWIN_AVC_INFO_H_
+#define _DARWIN_AVC_INFO_H_
+
+#ifdef USING_OSX_FIREWIRE
+
+// OS X headers
+#undef always_inline
+#include <IOKit/IOKitLib.h>
+#include <IOKit/firewire/IOFireWireLib.h>
+#include <IOKit/firewire/IOFireWireLibIsoch.h>
+#include <IOKit/firewire/IOFireWireFamilyCommon.h>
+#include <IOKit/avc/IOFireWireAVCLib.h>
+
+// Qt headers
+#include <qmap.h>
+
+// MythTV headers
+#include "firewiredevice.h"
+
+class DarwinFirewireDevice;
+
+class DarwinAVCInfo : public AVCInfo
+{
+  public:
+    DarwinAVCInfo() :
+        fw_node_ref(NULL), fw_device_ref(NULL),
+        fw_service_ref(NULL), avc_service_ref(NULL),
+        fw_device_notifier_ref(NULL),
+        avc_handle(NULL), fw_handle(NULL)
+    {
+        memset(unit_table, 0xff, sizeof(unit_table));
+    }
+
+    void Update(uint64_t _guid, DarwinFirewireDevice *dev,
+                IONotificationPortRef notify_port,
+                CFRunLoopRef &thread_cf_ref, io_object_t obj);
+
+    bool Open(CFRunLoopRef &thread_cf_ref);
+    void Close(void);
+
+    bool OpenAVCInterface(CFRunLoopRef &thread_cf_ref);
+    void CloseAVCInterface(void);
+
+    bool OpenDeviceInterface(CFRunLoopRef &thread_cf_ref);
+    void CloseDeviceInterface(void);
+
+    bool SendAVCCommand(
+        const vector<uint8_t> &cmd,
+        vector<uint8_t>       &result,
+        int                   retry_cnt);
+
+    bool IsAVCInterfaceOpen(void) const
+        { return avc_handle; }
+
+    bool IsOpen(void) const
+        { return fw_handle; }
+
+  public:
+    uint8_t      unit_table[32];
+
+    io_service_t fw_node_ref;     // parent of fw_device_ref
+    io_service_t fw_device_ref;   // parent of fw_service_ref
+    io_service_t fw_service_ref;  // parent of avc_service_ref
+    io_service_t avc_service_ref;
+
+    io_object_t  fw_device_notifier_ref;
+
+    IOFireWireAVCLibUnitInterface **avc_handle;
+    IOFireWireLibDeviceRef          fw_handle;
+};
+typedef QMap<uint64_t,DarwinAVCInfo*> avcinfo_list_t;
+
+#endif // USING_OSX_FIREWIRE
+
+#endif // _DARWIN_AVC_INFO_H_
Index: libs/libmythtv/mpeg/streamlisteners.h
===================================================================
--- libs/libmythtv/mpeg/streamlisteners.h	(revision 12321)
+++ libs/libmythtv/mpeg/streamlisteners.h	(working copy)
@@ -33,6 +33,16 @@
 class ServiceDescriptionTable;
 class DVBEventInformationTable;
 
+class TSDataListener
+{
+  public:
+    /// Callback function to add MPEG2 TS data
+    virtual void AddData(const unsigned char *data, uint dataSize) = 0;
+
+  protected:
+    virtual ~TSDataListener() { }
+};
+
 class MPEGStreamListener
 {
   protected:
Index: libs/libmythtv/darwinfirewirechannel.h
===================================================================
--- libs/libmythtv/darwinfirewirechannel.h	(revision 12321)
+++ libs/libmythtv/darwinfirewirechannel.h	(working copy)
@@ -1,42 +0,0 @@
-/**
- *  DarwinFirewireChannel
- *  Copyright (c) 2005 by Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-
-#ifndef LIBMYTHTV_DARWINFIREWIRECHANNEL_H
-#define LIBMYTHTV_DARWINFIREWIRECHANNEL_H
-
-#include <qstring.h>
-#include "tv_rec.h"
-#include "firewirechannelbase.h"
-
-
-namespace AVS
-{
-  class AVCDeviceController;
-  class AVCDevice;
-}
-
-class DarwinFirewireChannel : public FirewireChannelBase
-{
-  public:
-    DarwinFirewireChannel(FireWireDBOptions const&, TVRec *parent);
-
-    // Gets
-    AVS::AVCDevice* GetAVCDevice() const;
-
-    // Sets
-    bool SetChannelByNumber(int channel);
-
-  private:
-    bool OpenFirewire();
-    void CloseFirewire();
-
-  private:
-    AVS::AVCDeviceController* device_controller;
-    AVS::AVCDevice* device;
-};
-
-#endif
Index: libs/libmythtv/signalmonitor.cpp
===================================================================
--- libs/libmythtv/signalmonitor.cpp	(revision 12321)
+++ libs/libmythtv/signalmonitor.cpp	(working copy)
@@ -34,6 +34,11 @@
 #   include "iptvchannel.h"
 #endif
 
+#ifdef USING_FIREWIRE
+#   include "firewiresignalmonitor.h"
+#   include "firewirechannel.h"
+#endif
+
 #undef DBG_SM
 #define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \
     "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG);
@@ -117,6 +122,15 @@
     }
 #endif
 
+#ifdef USING_FIREWIRE
+    if (cardtype.upper() == "FIREWIRE")
+    {
+        FirewireChannel *fc = dynamic_cast<FirewireChannel*>(channel);
+        if (fc)
+            signalMonitor = new FirewireSignalMonitor(db_cardnum, fc);
+    }
+#endif
+
     if (!signalMonitor)
     {
         VERBOSE(VB_IMPORTANT,
Index: libs/libmythtv/firewiresignalmonitor.h
===================================================================
--- libs/libmythtv/firewiresignalmonitor.h	(revision 0)
+++ libs/libmythtv/firewiresignalmonitor.h	(revision 0)
@@ -0,0 +1,67 @@
+// -*- Mode: c++ -*-
+
+#ifndef _FIREWIRESIGNALMONITOR_H_
+#define _FIREWIRESIGNALMONITOR_H_
+
+#include <qmap.h>
+#include <qmutex.h>
+#include <qdatetime.h>
+
+#include "dtvsignalmonitor.h"
+#include "firewiredevice.h"
+#include "util.h"
+
+class FirewireChannel;
+
+class FirewireSignalMonitor : public DTVSignalMonitor, public TSDataListener
+{
+    Q_OBJECT
+
+  public:
+    FirewireSignalMonitor(int db_cardnum, FirewireChannel *_channel,
+                          uint _flags = kFWSigMon_WaitForPower,
+                          const char *_name = "FirewireSignalMonitor");
+
+    virtual void HandlePAT(const ProgramAssociationTable*);
+    virtual void HandlePMT(uint, const ProgramMapTable*);
+
+    void Stop(void);
+
+  public slots:
+    void deleteLater(void);
+
+  protected:
+    FirewireSignalMonitor(void);
+    FirewireSignalMonitor(const FirewireSignalMonitor&);
+    virtual ~FirewireSignalMonitor();
+
+    virtual void UpdateValues(void);
+    void EmitFirewireSignals(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 // _FIREWIRESIGNALMONITOR_H_
Index: libs/libmythtv/darwinfirewirerecorder.h
===================================================================
--- libs/libmythtv/darwinfirewirerecorder.h	(revision 12321)
+++ libs/libmythtv/darwinfirewirerecorder.h	(working copy)
@@ -1,62 +0,0 @@
-/**
- *  FirewireRecorder
- *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-#ifndef LIBMYTHTV_DARWINFIREWIRERECORDER_H_
-#define LIBMYTHTV_DARWINFIREWIRERECORDER_H_
-
-#include "firewirerecorderbase.h"
-#include "darwinfirewirechannel.h"
-
-//#include <IOKit/IOReturn.h>
-//#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
-
-typedef unsigned long UInt32;
-typedef int IOReturn;
-
-namespace AVS
-{
-  class AVCDeviceController;
-  class AVCDevice;
-  class StringLogger;
-  class AVCDeviceStream;
-}
-
-/** \class DarwinFirewireRecorder
- *  \brief This is a specialization of DTVRecorder used to
- *         handle DVB and ATSC streams from a firewire input.
- *
- *  \sa DTVRecorder
- */
-class DarwinFirewireRecorder : public FirewireRecorderBase
-{
-  public:
-    DarwinFirewireRecorder(TVRec *rec, ChannelBase* tuner);
-    ~DarwinFirewireRecorder();
-
-    bool Open(void); 
-
-    void SetOption(const QString &name, const QString &value);
-    void SetOption(const QString &name, int value);
-
-  private:
-    void Close();
-
-    void start();
-    void stop();
-    void no_data();
-    bool grab_frames();
-
-    static IOReturn MPEGNoData(void* pRefCon);
-    static IOReturn tspacket_callback(UInt32 tsPacketCount, UInt32 **ppBuf, void *pRefCon);
-
-    AVS::AVCDevice* capture_device;
-    AVS::StringLogger* message_log;
-    AVS::AVCDeviceStream* video_stream;
-
-    bool isopen;
-};
-
-#endif
Index: libs/libmythtv/cardutil.cpp
===================================================================
--- libs/libmythtv/cardutil.cpp	(revision 12321)
+++ libs/libmythtv/cardutil.cpp	(working copy)
@@ -680,27 +680,10 @@
 {
     QString label = QString::null;
 
-    if (cardtype == "FIREWIRE")
+    if (cardtype == "DBOX2")
     {
         MSqlQuery query(MSqlQuery::InitCon());
         query.prepare(
-            "SELECT firewire_port, firewire_node "
-            "FROM capturecard "
-            "WHERE cardid = :CARDID");
-        query.bindValue(":CARDID", cardid);
-
-        if (!query.exec() || !query.isActive() || !query.next())
-            label = "[ DB ERROR ]";
-        else
-            label = QString("[ FIREWIRE : Port %2 Node %3 ]")
-                .arg(query.value(0).toString())
-                .arg(query.value(1).toString());
- 
-    }
-    else if (cardtype == "DBOX2")
-    {
-        MSqlQuery query(MSqlQuery::InitCon());
-        query.prepare(
             "SELECT dbox2_host, dbox2_port, dbox2_httpport "
             "FROM capturecard "
             "WHERE cardid = :CARDID");
Index: libs/libmythtv/firewirechannel.h
===================================================================
--- libs/libmythtv/firewirechannel.h	(revision 12321)
+++ libs/libmythtv/firewirechannel.h	(working copy)
@@ -1,50 +1,52 @@
 /**
  *  FirewireChannel
- *  Copyright (c) 2005 by Jim Westfall
- *  SA3250HD support Copyright (c) 2005 by Matt Porter
+ *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
  *  Distributed as part of MythTV under GPL v2 and later.
  */
 
+#ifndef _FIREWIRECHANNEL_H_
+#define _FIREWIRECHANNEL_H_
 
-#ifndef FIREWIRECHANNEL_H
-#define FIREWIRECHANNEL_H
-
-#include <qstring.h>
 #include "tv_rec.h"
-#include "firewirechannelbase.h"
-#include <libavc1394/avc1394.h>
+#include "dtvchannel.h"
+#include "firewiredevice.h"
 
-using namespace std;
-
-class FirewireChannel : public FirewireChannelBase
+class FirewireChannel : public DTVChannel
 {
   public:
-    enum PowerState {
-        On,
-        Off,
-        Failed
-    };
+    FirewireChannel(TVRec *parent, const QString &videodevice,
+                    const FireWireDBOptions &firewire_opts);
+    ~FirewireChannel() { Close(); }
 
-    FirewireChannel(FireWireDBOptions firewire_opts, TVRec *parent);
-    ~FirewireChannel(void);
+    // Commands
+    virtual bool Open(void);
+    virtual void Close(void);
+    virtual bool SwitchToInput(const QString &inputname, const QString &chan);
+    virtual bool SwitchToInput(int newcapchannel, bool setstarting);
 
-    bool OpenFirewire(void); 
-    void CloseFirewire(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
-    void SetExternalChanger(void);
-    bool SetChannelByNumber(int channel);
+    virtual bool SetChannelByString(const QString &chan);
+    virtual bool SetChannelByNumber(int channel);
+    virtual bool SetPowerState(bool on);
 
     // Gets
-    bool IsOpen(void) const { return isopen; }
-    QString GetDevice(void) const
-        { return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node); }
-    PowerState GetPowerState(void);
+    virtual bool IsOpen(void) const { return isopen; }
+    virtual FirewireDevice::PowerState GetPowerState(void) const;
+    virtual QString GetDevice(void) const;
+    virtual FirewireDevice *GetFirewireDevice(void) { return device; }
 
-  private:
+  protected:
+    QString            videodevice;
     FireWireDBOptions  fw_opts;
-    nodeid_t           fwnode;
-    raw1394handle_t    fwhandle;
+    FirewireDevice    *device;
+    uint               current_channel;
+    bool               isopen;
 };
 
-#endif
+#endif // _FIREWIRECHANNEL_H_
Index: libs/libmythtv/videosource.cpp
===================================================================
--- libs/libmythtv/videosource.cpp	(revision 12321)
+++ libs/libmythtv/videosource.cpp	(working copy)
@@ -8,7 +8,8 @@
 #include <sys/stat.h>
 
 // C++ headers
-#include <iostream>
+#include <algorithm>
+using namespace std;
 
 // Qt headers
 #include <qapplication.h>
@@ -33,6 +34,7 @@
 #include "channelutil.h"
 #include "frequencies.h"
 #include "diseqcsettings.h"
+#include "firewiredevice.h"
 
 #ifdef USING_DVB
 #include "dvbtypes.h"
@@ -929,26 +931,75 @@
     };
 };
 
-class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage
+class FirewireGUID : public ComboBoxSetting, public CaptureCardDBStorage
 {
   public:
-    FirewireModel(const CaptureCard &parent) :
+    FirewireGUID(const CaptureCard &parent) :
         ComboBoxSetting(this),
-        CaptureCardDBStorage(this, parent, "firewire_model")
+        CaptureCardDBStorage(this, parent, "videodevice")
     {
-        setLabel(QObject::tr("Cable box model"));
-        addSelection(QObject::tr("Other"));
-        addSelection("DCT-6200");
-        addSelection("SA3250HD");
-	addSelection("SA4200HD");
-        QString help = QObject::tr(
-            "Choose the model that most closely resembles your set top box. "
-            "Depending on firmware revision SA4200HD may work better for a "
-            "SA3250HD box.");
-        setHelpText(help);
+        setLabel(QObject::tr("GUID"));
+#ifdef USING_FIREWIRE
+        vector<AVCInfo> list = FirewireDevice::GetSTBList();
+        for (uint i = 0; i < list.size(); i++)
+        {
+            QString guid = list[i].GetGUIDString();
+            guid_to_avcinfo[guid] = list[i];
+            addSelection(guid);
+        }
+#endif // USING_FIREWIRE
     }
+
+    AVCInfo GetAVCInfo(const QString &guid) const
+        { return guid_to_avcinfo[guid]; }
+
+  private:
+    QMap<QString,AVCInfo> guid_to_avcinfo;
 };
 
+FirewireModel::FirewireModel(const CaptureCard  &parent,
+                             const FirewireGUID *_guid) :
+    ComboBoxSetting(this),
+    CaptureCardDBStorage(this, parent, "firewire_model"),
+    guid(_guid)
+{
+    setLabel(QObject::tr("Cable box model"));
+    addSelection(QObject::tr("Generic"), "GENERIC");
+    addSelection("DCT-6200");
+    addSelection("DCT-6212");
+    addSelection("DCT-6216");
+    addSelection("SA3250HD");
+    addSelection("SA4200HD");
+    QString help = QObject::tr(
+        "Choose the model that most closely resembles your set top box. "
+        "Depending on firmware revision SA4200HD may work better for a "
+        "SA3250HD box.");
+    setHelpText(help);
+}
+
+void FirewireModel::SetGUID(const QString &_guid)
+{
+#ifdef USING_FIREWIRE
+    AVCInfo info = guid->GetAVCInfo(_guid);
+    QString model = FirewireDevice::GetModelName(info.vendorid, info.modelid);
+    setValue(max(getValueIndex(model), 0));
+#endif // USING_FIREWIRE
+}
+
+void FirewireDesc::SetGUID(const QString &_guid)
+{
+    setLabel(tr("Description"));
+
+#ifdef USING_FIREWIRE
+    QString name = guid->GetAVCInfo(_guid).product_name;
+    name.replace("Scientific-Atlanta", "SA");
+    name.replace(", Inc.", "");
+    name.replace("Explorer(R)", "");
+    name = name.simplifyWhiteSpace();
+    setValue((name.isEmpty()) ? "" : name);
+#endif // USING_FIREWIRE
+}
+
 class FirewireConnection : public ComboBoxSetting, public CaptureCardDBStorage
 {
   public:
@@ -962,32 +1013,6 @@
     }
 };
 
-class FirewirePort : public SpinBoxSetting, public CaptureCardDBStorage
-{
-  public:
-    FirewirePort(const CaptureCard &parent) :
-        SpinBoxSetting(this, 0, 63, 1),
-        CaptureCardDBStorage(this, parent, "firewire_port")
-    {
-        setValue(0);
-        setLabel(QObject::tr("IEEE-1394 Port"));
-        setHelpText(QObject::tr("Firewire port on your firewire card."));
-    }
-};
-
-class FirewireNode : public SpinBoxSetting, public CaptureCardDBStorage
-{
-  public:
-    FirewireNode(const CaptureCard &parent) :
-        SpinBoxSetting(this, 0, 63, 1),
-        CaptureCardDBStorage(this, parent, "firewire_node")
-    {
-        setValue(2);
-        setLabel(QObject::tr("Node"));
-        setHelpText(QObject::tr("Firewire node is the remote device."));
-    }
-};
-
 class FirewireSpeed : public ComboBoxSetting, public CaptureCardDBStorage
 {
   public:
@@ -999,6 +1024,7 @@
         addSelection(QObject::tr("100Mbps"),"0");
         addSelection(QObject::tr("200Mbps"),"1");
         addSelection(QObject::tr("400Mbps"),"2");
+        addSelection(QObject::tr("800Mbps"),"3");
     }
 };
 
@@ -1007,23 +1033,35 @@
   public:
     FirewireConfigurationGroup(CaptureCard& a_parent) :
         VerticalConfigurationGroup(false, true, false, false),
-        parent(a_parent)
+        parent(a_parent),
+        dev(new FirewireGUID(parent)),
+        desc(new FirewireDesc(dev)),
+        model(new FirewireModel(parent, dev))
     {
-        HorizontalConfigurationGroup *hg0 =
-            new HorizontalConfigurationGroup(false, false, true, true);
-        hg0->addChild(new FirewireModel(parent));
-        hg0->addChild(new FirewireConnection(parent));
-        addChild(hg0);
-        HorizontalConfigurationGroup *hg1 =
-            new HorizontalConfigurationGroup(false, false, true, true);
-        hg1->addChild(new FirewirePort(parent));
-        hg1->addChild(new FirewireNode(parent));
-        hg1->addChild(new FirewireSpeed(parent));
-        addChild(hg1);
+        addChild(dev);
+        addChild(desc);
+        addChild(model);
+
+#ifdef USING_LINUX_FIREWIRE
+        addChild(new FirewireConnection(parent));
+        addChild(new FirewireSpeed(parent));
+#endif // USING_LINUX_FIREWIRE
+
+        addChild(new SignalTimeout(parent, 2000, 1000));
+        addChild(new ChannelTimeout(parent, 9000, 1750));
         addChild(new SingleCardInput(parent));
+
+        connect(dev,   SIGNAL(valueChanged(const QString&)),
+                model, SLOT(  SetGUID(     const QString&)));
+        connect(dev,   SIGNAL(valueChanged(const QString&)),
+                desc,  SLOT(  SetGUID(     const QString&)));
     };
+
   private:
-    CaptureCard &parent;
+    CaptureCard   &parent;
+    FirewireGUID  *dev;
+    FirewireDesc  *desc;
+    FirewireModel *model;
 };
 
 class DBOX2Port : public LineEditSetting, public CaptureCardDBStorage
Index: libs/libmythtv/selectavcdevice.cpp
===================================================================
--- libs/libmythtv/selectavcdevice.cpp	(revision 12321)
+++ libs/libmythtv/selectavcdevice.cpp	(working copy)
@@ -1,47 +0,0 @@
-/**
- *  SelectAVCDevice
- *  Copyright (c) 2006 by Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-#include "mythconfig.h"
-
-#ifdef CONFIG_DARWIN
-# include "mythcontext.h"
-# include "selectavcdevice.h"
-# undef always_inline
-# include <AVCVideoServices/AVCVideoServices.h>
-
-AVS::AVCDevice* SelectAVCDevice(
-    AVS::AVCDeviceController* controller, 
-    bool (*filter)(AVS::AVCDevice*)
-)
-{
-    VERBOSE(VB_GENERAL, QString("SelectAVCDevice:"));
-
-    for (unsigned n = CFArrayGetCount(controller->avcDeviceArray), 
-             i = 0; i < n; ++i)
-    {
-        AVS::AVCDevice& d = *(AVS::AVCDevice*)CFArrayGetValueAtIndex(controller->avcDeviceArray, i);
-
-        VERBOSE(
-            VB_GENERAL, 
-            QString("SelectAVCDevice: %1, format: %2, attached: %3, type: %4")
-                .arg(d.deviceName)
-                .arg(d.isDVDevice ? "DV" : d.isMPEGDevice ? "MPEG2-TS" : "unknown")
-                .arg(d.isAttached ? "yes" : "no")
-                .arg(d.hasTapeSubunit ? "tape" : d.hasMonitorOrTunerSubunit ? "tuner" : "unknown")
-        );
-
-        if (filter(&d))
-        {
-            VERBOSE(VB_GENERAL, QString("SelectAVCDevice: FOUND"));
-            return &d;
-        }
-    }
-    VERBOSE(VB_GENERAL, QString("SelectAVCDevice: NOT FOUND"));
-    return 0;
-}
-
-#endif // CONFIG_DARWIN
-
Index: libs/libmythtv/firewirechannelbase.cpp
===================================================================
--- libs/libmythtv/firewirechannelbase.cpp	(revision 12321)
+++ libs/libmythtv/firewirechannelbase.cpp	(working copy)
@@ -1,57 +0,0 @@
-/**
- *  FirewireChannelBase
- *  Copyright (c) 2005 by Jim Westfall Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-
-#include <iostream>
-#include "mythcontext.h"
-#include "firewirechannelbase.h"
-
-bool FirewireChannelBase::SetChannelByString(const QString &chan)
-{
-    inputs[currentInputID]->startChanNum = chan; 
-    curchannelname = chan;
-
-    InputMap::const_iterator it = inputs.find(currentInputID);
-
-    if (!(*it)->externalChanger.isEmpty()) 
-        return ChangeExternalChannel(chan);
-
-    return isopen && SetChannelByNumber(chan.toInt());
-}
-
-bool FirewireChannelBase::Open()
-{
-    if (!InitializeInputs()) 
-        return false; 
-
-    InputMap::const_iterator it = inputs.find(currentInputID); 
-    if (!(*it)->externalChanger.isEmpty()) 
-        return true;
-
-    if (!isopen)
-    {
-        isopen = OpenFirewire(); 
-        return isopen; 
-    }
-    return true;
-}
-
-void FirewireChannelBase::Close()
-{
-    if (isopen)
-        CloseFirewire();
-    isopen = false;
-}
-    
-bool FirewireChannelBase::SwitchToInput(const QString &input,
-                                        const QString &chan)
-{
-    int inputNum = GetInputByName(input); 
-    if (inputNum < 0) 
-        return false;
-
-    return SetChannelByString(chan);
-}
Index: libs/libmythtv/linuxfirewiredevice.h
===================================================================
--- libs/libmythtv/linuxfirewiredevice.h	(revision 0)
+++ libs/libmythtv/linuxfirewiredevice.h	(revision 0)
@@ -0,0 +1,90 @@
+/**
+ *  LinuxFirewireDevice
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef _LINUX_FIREWIRE_DEVICE_H_
+#define _LINUX_FIREWIRE_DEVICE_H_
+
+#include "firewiredevice.h"
+
+class LFDPriv;
+
+class LinuxFirewireDevice : public FirewireDevice
+{
+    friend void *linux_firewire_device_streaming_thunk(void *param);
+    friend int linux_firewire_device_tspacket_handler(
+        unsigned char *tspacket, int len, uint dropped, void *callback_data);
+
+  public:
+    LinuxFirewireDevice(uint64_t guid, uint subunitid,
+                        uint speed, bool use_p2p,
+                        uint av_buffer_size_in_bytes = 0);
+    ~LinuxFirewireDevice();
+
+    // Commands
+    virtual bool OpenPort(void);
+    virtual bool ClosePort(void);
+    void HandleBusReset(uint);
+
+    virtual void AddListener(TSDataListener*);
+    virtual void RemoveListener(TSDataListener*);
+
+    // Gets
+    virtual bool IsPortOpen(void) const;
+
+    // Statics
+    static vector<AVCInfo> GetSTBList(void);
+
+    // Constants
+    static const uint kBroadcastChannel;
+    static const uint kConnectionP2P;
+    static const uint kConnectionBroadcast;
+    static const uint kMaxBufferedPackets;
+
+  private:
+    bool GetPortAndNode(void);
+
+    bool OpenNode(void);
+    bool CloseNode(void);
+
+    bool OpenAVStream(void);
+    bool CloseAVStream(void);
+
+    bool OpenP2PNode(void);
+    bool CloseP2PNode(void);
+
+    bool OpenBroadcastNode(void);
+    bool CloseBroadcastNode(void);
+
+    bool StartStreaming(void);
+    bool StopStreaming(void);
+    bool StopStreamingLater(void);
+
+    bool ResetBus(void);
+
+    void RunStreaming(void);
+    bool LoopIteration(uint timeout_in_msec);
+    void PrintDropped(uint dropped_packets);
+
+    bool SetAVStreamBufferSize(uint size_in_bytes);
+    bool SetAVStreamSpeed(uint speed);
+
+    bool IsNodeOpen(void) const;
+    bool IsAVStreamOpen(void) const;
+
+    virtual bool SendAVCCommand(const vector<uint8_t> &cmd,
+                                vector<uint8_t>       &result,
+                                int                    retry_cnt);
+
+  private:
+    int                      m_port;
+    int                      m_node;
+    uint                     m_bufsz;
+    bool                     m_use_p2p;
+    bool                     m_resetting;
+    LFDPriv                 *m_priv;
+};
+
+#endif // _LINUX_FIREWIRE_DEVICE_H_
Index: libs/libmythtv/tv_rec.cpp
===================================================================
--- libs/libmythtv/tv_rec.cpp	(revision 12321)
+++ libs/libmythtv/tv_rec.cpp	(working copy)
@@ -48,6 +48,7 @@
 #include "dbox2channel.h"
 #include "hdhrchannel.h"
 #include "iptvchannel.h"
+#include "firewirechannel.h"
 
 #include "recorderbase.h"
 #include "NuppelVideoRecorder.h"
@@ -57,21 +58,12 @@
 #include "dbox2recorder.h"
 #include "hdhrrecorder.h"
 #include "iptvrecorder.h"
+#include "firewirerecorder.h"
 
 #ifdef USING_V4L
 #include "channel.h"
 #endif
 
-#ifdef USING_FIREWIRE
-#ifdef CONFIG_DARWIN
-#include "darwinfirewirerecorder.h"
-#include "darwinfirewirechannel.h"
-#else 
-#include "firewirerecorder.h"
-#include "firewirechannel.h"
-#endif 
-#endif
-
 #define DEBUG_CHANNEL_PREFIX 0 /**< set to 1 to channel prefixing */
 
 #define LOC QString("TVRec(%1): ").arg(cardid)
@@ -158,11 +150,7 @@
     else if (genOpt.cardtype == "FIREWIRE")
     {
 #ifdef USING_FIREWIRE
-# ifdef CONFIG_DARWIN
-        channel = new DarwinFirewireChannel(fwOpt, this);
-# else 
-        channel = new FirewireChannel(fwOpt, this);
-# endif
+        channel = new FirewireChannel(this, genOpt.videodev, fwOpt);
         if (!channel->Open())
             return false;
         InitChannel(genOpt.defaultinput, startchannel);
@@ -831,16 +819,7 @@
     else if (genOpt.cardtype == "FIREWIRE")
     {
 #ifdef USING_FIREWIRE
-# ifdef CONFIG_DARWIN
-        recorder = new DarwinFirewireRecorder(this, this->channel);
-# else 
-        recorder = new FirewireRecorder(this);
-        recorder->SetOption("port",       fwOpt.port);
-        recorder->SetOption("node",       fwOpt.node);
-        recorder->SetOption("speed",      fwOpt.speed);
-        recorder->SetOption("model",      fwOpt.model);
-        recorder->SetOption("connection", fwOpt.connection);
-# endif // !CONFIG_DARWIN 
+        recorder = new FirewireRecorder(this, GetFirewireChannel());
 #endif // USING_FIREWIRE
     }
     else if (genOpt.cardtype == "DBOX2")
@@ -1114,6 +1093,15 @@
 #endif // USING_DVB
 }
 
+FirewireChannel *TVRec::GetFirewireChannel(void)
+{
+#ifdef USING_FIREWIRE
+    return dynamic_cast<FirewireChannel*>(channel);
+#else
+    return NULL;
+#endif // USING_FIREWIRE
+}
+
 Channel *TVRec::GetV4LChannel(void)
 {
 #ifdef USING_V4L
@@ -1418,8 +1406,7 @@
         ""
         "       dvb_on_demand,    dvb_tuning_delay, "
         ""
-        "       firewire_port,    firewire_node,       firewire_speed,  "
-        "       firewire_model,   firewire_connection,                  "
+        "       firewire_speed,   firewire_model,      firewire_connection, "
         ""
         "       dbox2_port,       dbox2_host,          dbox2_httpport   "
         ""
@@ -1479,18 +1466,16 @@
 
     // Firewire options
     uint fireoff = dvboff + 2;
-    firewire_opts.port        = query.value(fireoff + 0).toUInt();
-    firewire_opts.node        = query.value(fireoff + 1).toUInt(); 
-    firewire_opts.speed       = query.value(fireoff + 2).toUInt();
+    firewire_opts.speed       = query.value(fireoff + 0).toUInt();
 
-    test = query.value(fireoff + 3).toString();
+    test = query.value(fireoff + 1).toString();
     if (test != QString::null)
         firewire_opts.model = QString::fromUtf8(test);
 
-    firewire_opts.connection  = query.value(fireoff + 4).toUInt();
+    firewire_opts.connection  = query.value(fireoff + 2).toUInt();
 
     // DBOX2/HDHomeRun options
-    uint dbox2off = fireoff + 5;
+    uint dbox2off = fireoff + 3;
     dbox2_opts.port = query.value(dbox2off + 0).toUInt();
 
     test = query.value(dbox2off + 1).toString();
Index: libs/libmythtv/tv_rec.h
===================================================================
--- libs/libmythtv/tv_rec.h	(revision 12321)
+++ libs/libmythtv/tv_rec.h	(working copy)
@@ -35,6 +35,7 @@
 class DBox2Channel;
 class DTVChannel;
 class DVBChannel;
+class FirewireChannel;
 class Channel;
 class HDHRChannel;
 
@@ -85,11 +86,8 @@
 class FireWireDBOptions
 {
   public:
-    FireWireDBOptions() :
-        port(-1), node(-1), speed(-1), connection(-1), model("") {;}
-        
-    int port;
-    int node;
+    FireWireDBOptions() : speed(-1), connection(-1), model("") {;}
+
     int speed;
     int connection;
     QString model;
@@ -261,6 +259,7 @@
     DTVChannel   *GetDTVChannel(void);
     HDHRChannel  *GetHDHRChannel(void);
     DVBChannel   *GetDVBChannel(void);
+    FirewireChannel *GetFirewireChannel(void);
     Channel      *GetV4LChannel(void);
 
     bool SetupSignalMonitor(bool enable_table_monitoring, bool notify);
Index: libs/libmythtv/selectavcdevice.h
===================================================================
--- libs/libmythtv/selectavcdevice.h	(revision 12321)
+++ libs/libmythtv/selectavcdevice.h	(working copy)
@@ -1,24 +0,0 @@
-/**
- *  SelectAVCDevice
- *  Copyright (c) 2006 by Dave Abrahams
- *  Distributed as part of MythTV under GPL v2 and later.
- */
-
-#ifndef LIBMYTHTV_SELECTAVCDEVICE_H_
-# define LIBMYTHTV_SELECTAVCDEVICE_H_
-
-# include "mythconfig.h"
-
-# ifdef CONFIG_DARWIN
-#  undef always_inline
-#  include <AVCVideoServices/AVCVideoServices.h>
-
-AVS::AVCDevice* SelectAVCDevice(
-    AVS::AVCDeviceController*, 
-    bool (*)(AVS::AVCDevice*)
-);
-
-# endif // CONFIG_DARWIN
-
-#endif LIBMYTHTV_SELECTAVCDEVICE_H_ 
-
Index: libs/libmythtv/firewiredevice.h
===================================================================
--- libs/libmythtv/firewiredevice.h	(revision 0)
+++ libs/libmythtv/firewiredevice.h	(revision 0)
@@ -0,0 +1,280 @@
+/**
+ *  FirewireDevice
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef _FIREWIRE_DEVICE_H_
+#define _FIREWIRE_DEVICE_H_
+
+// C++ headers
+#include <vector>
+using namespace std;
+
+// Qt headers
+#include <qstring.h>
+#include <qmutex.h>
+
+// MythTV headers
+#include "streamlisteners.h"
+
+class TSPacket;
+
+class AVCInfo
+{
+  public:
+    int      port;
+    int      node;
+    uint64_t guid;
+    uint     specid;
+    uint     vendorid;
+    uint     modelid;
+    uint     firmware_revision;
+    QString  product_name;
+
+    AVCInfo();
+    AVCInfo(const AVCInfo &o);
+    AVCInfo &operator=(const AVCInfo &o);
+
+    QString GetGUIDString(void) const;
+};
+
+class FirewireDevice
+{
+  public:
+
+    // Public enums
+    typedef enum
+    {
+        kAVCPowerOn,
+        kAVCPowerOff,
+        kAVCPowerUnknown,
+        kAVCPowerQueryFailed,
+    } PowerState;
+
+    // AVC commands
+    typedef enum
+    {
+        kAVCControlCommand         = 0x00,
+        kAVCStatusInquiryCommand   = 0x01,
+        kAVCSpecificInquiryCommand = 0x02,
+        kAVCNotifyCommand          = 0x03,
+        kAVCGeneralInquiryCommand  = 0x04,
+
+        kAVCNotImplementedStatus   = 0x08,
+        kAVCAcceptedStatus         = 0x09,
+        kAVCRejectedStatus         = 0x0a,
+        kAVCInTransitionStatus     = 0x0b,
+        kAVCImplementedStatus      = 0x0c,
+        kAVCChangedStatus          = 0x0d,
+
+        kAVCInterimStatus          = 0x0f,
+        kAVCResponseImplemented    = 0x0c,
+    } IEEE1394Command;
+
+    // AVC unit addresses
+    typedef enum
+    {
+        kAVCSubunitId0                = 0x00,
+        kAVCSubunitId1                = 0x01,
+        kAVCSubunitId2                = 0x02,
+        kAVCSubunitId3                = 0x03,
+        kAVCSubunitId4                = 0x04,
+        kAVCSubunitIdExtended         = 0x05,
+        kAVCSubunitIdIgnore           = 0x07,
+
+        kAVCSubunitTypeVideoMonitor   = (0x00 << 3),
+        kAVCSubunitTypeAudio          = (0x01 << 3),
+        kAVCSubunitTypePrinter        = (0x02 << 3),
+        kAVCSubunitTypeDiscRecorder   = (0x03 << 3),
+        kAVCSubunitTypeTapeRecorder   = (0x04 << 3),
+        kAVCSubunitTypeTuner          = (0x05 << 3),
+        kAVCSubunitTypeCA             = (0x06 << 3),
+        kAVCSubunitTypeVideoCamera    = (0x07 << 3),
+        kAVCSubunitTypePanel          = (0x09 << 3),
+        kAVCSubunitTypeBulletinBoard  = (0x0a << 3),
+        kAVCSubunitTypeCameraStorage  = (0x0b << 3),
+        kAVCSubunitTypeMusic          = (0x0c << 3),
+        kAVCSubunitTypeVendorUnique   = (0x1c << 3),
+        kAVCSubunitTypeExtended       = (0x1e << 3),
+        kAVCSubunitTypeUnit           = (0x1f << 3),
+    } IEEE1394UnitAddress;
+
+    // AVC opcode
+    typedef enum
+    {
+        // Unit
+        kAVCUnitPlugInfoOpcode               = 0x02,
+        kAVCUnitDigitalOutputOpcode          = 0x10,
+        kAVCUnitDigitalInputOpcode           = 0x11,
+        kAVCUnitChannelUsageOpcode           = 0x12,
+        kAVCUnitOutputPlugSignalFormatOpcode = 0x18,
+        kAVCUnitInputPlugSignalFormatOpcode  = 0x19,
+        kAVCUnitConnectAVOpcode              = 0x20,
+        kAVCUnitDisconnectAVOpcode           = 0x21,
+        kAVCUnitConnectionsOpcode            = 0x22,
+        kAVCUnitConnectOpcode                = 0x24,
+        kAVCUnitDisconnectOpcode             = 0x25,
+        kAVCUnitUnitInfoOpcode               = 0x30,
+        kAVCUnitSubunitInfoOpcode            = 0x31,
+        kAVCUnitSignalSourceOpcode           = 0x1a,
+        kAVCUnitPowerOpcode                  = 0xb2,
+
+        // Common Unit + Subunit
+        kAVCCommonOpenDescriptorOpcode       = 0x08,
+        kAVCCommonReadDescriptorOpcode       = 0x09,
+        kAVCCommonWriteDescriptorOpcode      = 0x0A,
+        kAVCCommonSearchDescriptorOpcode     = 0x0B,
+        kAVCCommonObjectNumberSelectOpcode   = 0x0D,
+        kAVCCommonPowerOpcode                = 0xB2,
+        kAVCCommonReserveOpcode              = 0x01,
+        kAVCCommonPlugInfoOpcode             = 0x02,
+        kAVCCommonVendorDependentOpcode      = 0x00,
+
+        // Panel
+        kAVCPanelPassThrough                 = 0x7c,
+    } IEEE1394Opcode;
+
+    // AVC param 0
+    typedef enum
+    {
+        kAVCPowerStateOn           = 0x70,
+        kAVCPowerStateOff          = 0x60,
+        kAVCPowerStateQuery        = 0x7f,
+    } IEEE1394UnitPowerParam0;
+
+    typedef enum
+    {
+        kAVCPanelKeySelect          = 0x00,
+        kAVCPanelKeyUp              = 0x01,
+        kAVCPanelKeyDown            = 0x02,
+        kAVCPanelKeyLeft            = 0x03,
+        kAVCPanelKeyRight           = 0x04,
+        kAVCPanelKeyRightUp         = 0x05,
+        kAVCPanelKeyRightDown       = 0x06,
+        kAVCPanelKeyLeftUp          = 0x07,
+        kAVCPanelKeyLeftDown        = 0x08,
+        kAVCPanelKeyRootMenu        = 0x09,
+        kAVCPanelKeySetupMenu       = 0x0A,
+        kAVCPanelKeyContentsMenu    = 0x0B,
+        kAVCPanelKeyFavoriteMenu    = 0x0C,
+        kAVCPanelKeyExit            = 0x0D,
+
+        kAVCPanelKey0               = 0x20,
+        kAVCPanelKey1               = 0x21,
+        kAVCPanelKey2               = 0x22,
+        kAVCPanelKey3               = 0x23,
+        kAVCPanelKey4               = 0x24,
+        kAVCPanelKey5               = 0x25,
+        kAVCPanelKey6               = 0x26,
+        kAVCPanelKey7               = 0x27,
+        kAVCPanelKey8               = 0x28,
+        kAVCPanelKey9               = 0x29,
+        kAVCPanelKeyDot             = 0x2A,
+        kAVCPanelKeyEnter           = 0x2B,
+        kAVCPanelKeyClear           = 0x2C,
+
+        kAVCPanelKeyChannelUp       = 0x30,
+        kAVCPanelKeyChannelDown     = 0x31,
+        kAVCPanelKeyPreviousChannel = 0x32,
+        kAVCPanelKeySoundSelect     = 0x33,
+        kAVCPanelKeyInputSelect     = 0x34,
+        kAVCPanelKeyDisplayInfo     = 0x35,
+        kAVCPanelKeyHelp            = 0x36,
+        kAVCPanelKeyPageUp          = 0x37,
+        kAVCPanelKeyPageDown        = 0x38,
+
+        kAVCPanelKeyPower           = 0x40,
+        kAVCPanelKeyVolumeUp        = 0x41,
+        kAVCPanelKeyVolumeDown      = 0x42,
+        kAVCPanelKeyMute            = 0x43,
+        kAVCPanelKeyPlay            = 0x44,
+        kAVCPanelKeyStop            = 0x45,
+        kAVCPanelKeyPause           = 0x46,
+        kAVCPanelKeyRecord          = 0x47,
+        kAVCPanelKeyRewind          = 0x48,
+        kAVCPanelKeyFastForward     = 0x49,
+        kAVCPanelKeyEject           = 0x4a,
+        kAVCPanelKeyForward         = 0x4b,
+        kAVCPanelKeyBackward        = 0x4c,
+
+        kAVCPanelKeyAngle           = 0x50,
+        kAVCPanelKeySubPicture      = 0x51,
+
+        kAVCPanelKeyTuneFunction    = 0x67,
+
+        kAVCPanelKeyPress           = 0x00,
+        kAVCPanelKeyRelease         = 0x80,
+
+    } IEEE1394PanelPassThroughParam0;
+
+    virtual ~FirewireDevice() { }
+
+    // Commands
+    virtual bool OpenPort(void) = 0;
+    virtual bool ClosePort(void) = 0;
+
+    virtual void AddListener(TSDataListener*);
+    virtual void RemoveListener(TSDataListener*);
+
+    // Sets
+    virtual bool SetPowerState(bool on);
+    virtual bool SetChannel(const QString &panel_model,
+                            uint alt_method, uint channel);
+
+    // Gets
+    virtual bool IsPortOpen(void) const = 0;
+    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
+
+    // non-const Gets
+    virtual PowerState GetPowerState(void);
+
+    // Statics
+    static inline bool IsSTBSupported(const QString &model);
+    static QString GetModelName(uint vendorid, uint modelid);
+    static vector<AVCInfo> GetSTBList(void);
+    static bool IsSubunitType(
+        const uint8_t unit_table[32], IEEE1394UnitAddress subunit_type);
+    static QString GetSubunitInfoString(const uint8_t table[32]);
+
+  protected:
+    FirewireDevice(uint64_t guid, uint subunitid, uint speed);
+
+    virtual bool SendAVCCommand(const vector<uint8_t> &cmd,
+                                vector<uint8_t> &result,
+                                int retry_cnt) = 0;
+    bool GetSubunitInfo(uint8_t table[32]);
+
+    void SetLastChannel(uint channel);
+    void ProcessPATPacket(const TSPacket&);
+    virtual void BroadcastToListeners(
+        const unsigned char *data, uint dataSize);
+
+    uint64_t                 m_guid;
+    uint                     m_subunitid;
+    uint                     m_speed;
+    uint                     m_last_channel;
+    uint                     m_last_crc;
+    bool                     m_buffer_cleared;
+
+    uint                     m_open_port_cnt;
+    vector<TSDataListener*>  m_listeners;
+    mutable QMutex           m_lock;
+
+    /// Vendor ID + Model ID to FirewireDevice STB model string
+    static QMap<uint64_t,QString> s_id_to_model;
+    static QMutex                 s_static_lock;
+};
+
+inline bool FirewireDevice::IsSTBSupported(const QString &panel_model)
+{
+    QString model = panel_model.upper();
+    return ((model == "DCT-6200") ||
+            (model == "DCT-6212") ||
+            (model == "DCT-6216") ||
+            (model == "SA3250HD") ||
+            (model == "SA4200HD") ||
+            (model == "GENERIC"));
+}
+
+#endif // _FIREWIRE_DEVICE_H_
Index: libs/libmythtv/linuxfirewiredevice.cpp
===================================================================
--- libs/libmythtv/linuxfirewiredevice.cpp	(revision 0)
+++ libs/libmythtv/linuxfirewiredevice.cpp	(revision 0)
@@ -0,0 +1,919 @@
+/**
+ *  LinuxFirewireDevice
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Copyright (c) 2006 by Daniel Kristjansson
+ *  SA3250HD support Copyright (c) 2005 by Matt Porter
+ *  SA4200HD/Alternate 3250 support Copyright (c) 2006 by Chris Ingrassia
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// POSIX headers
+#include <pthread.h>
+#include <sys/select.h>
+
+#include <cassert>
+
+// Linux headers
+#include <libraw1394/raw1394.h>
+#include <libraw1394/csr.h>
+#include <libiec61883/iec61883.h>
+#include <libavc1394/avc1394.h>
+#include <libavc1394/rom1394.h>
+
+//#include <unistd.h>
+//#include <string.h>
+//#include <stdio.h>
+//#include <stdlib.h>
+#include <netinet/in.h>
+
+// C++ headers
+#include <algorithm>
+using namespace std;
+
+// Qt headers
+#include <qdatetime.h>
+
+// MythTV headers
+#include "linuxfirewiredevice.h"
+#include "firewirerecorder.h"
+#include "mythcontext.h"
+
+#define LOC      QString("LFireDev(%1:%2): ").arg(m_port).arg(m_node)
+#define LOC_WARN QString("LFireDev(%1:%2), Warning: ").arg(m_port).arg(m_node)
+#define LOC_ERR  QString("LFireDev(%1:%2), Error: ").arg(m_port).arg(m_node)
+
+#define kNoDataTimeout            50 /* msec */
+
+typedef QMap<raw1394handle_t,LinuxFirewireDevice*> handle_to_lfd_t;
+
+class LFDPriv
+{
+  public:
+    LFDPriv() :
+        handle(NULL), generation(0), reset_start(true),
+        avstream(NULL), channel(-1),
+        is_p2p_node_open(false), is_bcast_node_open(false),
+        is_streaming(false), is_streaming_running(false)
+    {
+        memset(unit_table, 0xff, sizeof(unit_table));
+    }
+
+    raw1394handle_t  handle;
+    uint             generation;
+    bool             reset_start;
+    uint8_t          unit_table[32];
+
+    iec61883_mpeg2_t avstream;
+    int              channel;
+
+    bool             is_p2p_node_open;
+    bool             is_bcast_node_open;
+    bool             is_streaming;
+    bool             is_streaming_running;
+
+    QDateTime        stop_streaming_timer;
+    pthread_t        streaming_thread;
+    QMutex           start_stop_streaming_lock;
+
+    static QMutex          s_lock;
+    static handle_to_lfd_t s_handle_info;
+};
+QMutex          LFDPriv::s_lock;
+handle_to_lfd_t LFDPriv::s_handle_info;
+
+const uint LinuxFirewireDevice::kBroadcastChannel    = 63;
+const uint LinuxFirewireDevice::kConnectionP2P       = 0;
+const uint LinuxFirewireDevice::kConnectionBroadcast = 1;
+const uint LinuxFirewireDevice::kMaxBufferedPackets  = 2000;
+
+// callback function for libiec61883
+int linux_firewire_device_tspacket_handler(
+    unsigned char *tspacket, int len, uint dropped, void *callback_data);
+static QString speed_to_string(uint speed);
+static int linux_firewire_device_bus_reset_handler(
+    raw1394handle_t handle, uint generation);
+static uint64_t get_guid(raw1394handle_t handle, nodeid_t node);
+
+LinuxFirewireDevice::LinuxFirewireDevice(
+    uint64_t guid, uint subunitid,
+    uint speed, bool use_p2p, uint av_buffer_size_in_bytes) :
+    FirewireDevice(guid, subunitid, speed),
+    m_port(-1),         m_node(-1),
+    m_bufsz(av_buffer_size_in_bytes),
+    m_use_p2p(use_p2p), m_resetting(false),
+    m_priv(new LFDPriv())
+{
+    if (!m_bufsz)
+        m_bufsz = gContext->GetNumSetting("HDRingbufferSize");
+}
+
+LinuxFirewireDevice::~LinuxFirewireDevice()
+{
+    if (IsPortOpen())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
+        while (IsPortOpen())
+            ClosePort();
+    }
+
+    if (m_priv)
+    {
+        delete m_priv;
+        m_priv = NULL;
+    }
+}
+
+void LinuxFirewireDevice::HandleBusReset(uint generation)
+{
+    QString loc = LOC + QString("HandleBusReset(%1->%2)")
+        .arg(m_priv->generation).arg(generation);
+
+    m_priv->generation = generation;
+
+    if (m_priv->reset_start)
+    {
+        m_priv->reset_start = false;
+        if (m_priv->is_streaming)
+        {
+            VERBOSE(VB_IMPORTANT, loc + ": Stopping Streaming");
+            iec61883_mpeg2_recv_stop(m_priv->avstream);
+            VERBOSE(VB_IMPORTANT, loc + ": Stopped Streaming");
+        }
+        return;
+    }
+    m_priv->reset_start = true;
+
+    raw1394_update_generation(m_priv->handle, generation);
+
+    if (m_priv->channel >= 0)
+    {
+        int bandwidth = 1;
+        int oplug = -1, iplug = -1;
+        int fwchan = iec61883_cmp_reconnect(
+            m_priv->handle, m_node | 0xffc0, &oplug,
+            raw1394_get_local_id(m_priv->handle), &iplug,
+            &bandwidth, m_priv->channel);
+
+        if (fwchan < 0)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset: Failed to reconnect");
+        }
+        else if (fwchan != m_priv->channel)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_WARN + QString("FWChan changed %1->%2")
+                    .arg(m_priv->channel).arg(fwchan));
+        }
+        m_priv->channel = fwchan;
+
+        VERBOSE(VB_IMPORTANT, loc + ": Reconnected fwchan: "<<fwchan);
+
+        if (m_priv->is_streaming)
+        {
+            VERBOSE(VB_IMPORTANT, loc + ": Starting Streaming");
+            iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel);
+            VERBOSE(VB_IMPORTANT, loc + ": Started Streaming");
+        }
+    }
+}
+
+bool LinuxFirewireDevice::OpenPort(void)
+{
+    QMutexLocker mlocker(&m_lock);
+    QMutexLocker slocker(&LFDPriv::s_lock);
+
+    VERBOSE(VB_RECORD, LOC + "OpenPort()");
+
+    if (m_priv->handle)
+    {
+        m_open_port_cnt++;
+        return true;
+    }
+
+    if (!GetPortAndNode())
+        return false;
+
+    VERBOSE(VB_RECORD, LOC + "Getting raw1394 handle "<<(m_open_port_cnt-1));
+    m_priv->handle = raw1394_new_handle_on_port(m_port);
+
+    if (!m_priv->handle)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get handle for " +
+                QString("port: %1").arg(m_port) + ENO);
+
+        return false;
+    }
+
+    LFDPriv::s_handle_info[m_priv->handle] = this;
+
+    m_priv->generation = raw1394_get_generation(m_priv->handle);
+    raw1394_set_bus_reset_handler(
+        m_priv->handle, linux_firewire_device_bus_reset_handler);
+
+    GetSubunitInfo(m_priv->unit_table);
+    VERBOSE(VB_RECORD, LOC + GetSubunitInfoString(m_priv->unit_table));
+
+    if (!IsSubunitType(m_priv->unit_table, kAVCSubunitTypeTuner) ||
+        !IsSubunitType(m_priv->unit_table, kAVCSubunitTypePanel))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("No STB at guid: 0x%1")
+                .arg(m_guid,0,16));
+
+        ClosePort();
+        return false;
+    }
+
+    m_open_port_cnt++;
+
+    return true;
+}
+
+bool LinuxFirewireDevice::ClosePort(void)
+{
+    QMutexLocker mlocker(&m_lock);
+    QMutexLocker slocker(&LFDPriv::s_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 (m_priv->handle)
+    {
+        if (IsNodeOpen())
+            CloseNode();
+
+        VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle "<<m_open_port_cnt);
+        raw1394_destroy_handle(m_priv->handle);
+        LFDPriv::s_handle_info.erase(m_priv->handle);
+        m_priv->handle = NULL;
+    }
+
+    return true;
+}
+
+void LinuxFirewireDevice::AddListener(TSDataListener *listener)
+{
+    FirewireDevice::AddListener(listener);
+
+    QMutexLocker locker(&m_lock);
+    if (!m_listeners.empty())
+    {
+        OpenNode();
+        OpenAVStream();
+        StartStreaming();
+    }
+}
+
+void LinuxFirewireDevice::RemoveListener(TSDataListener *listener)
+{
+    FirewireDevice::RemoveListener(listener);
+
+    QMutexLocker locker(&m_lock);
+    if (m_listeners.empty())
+    {
+        StopStreaming();
+        CloseAVStream();
+        CloseNode();
+    }
+}
+
+bool LinuxFirewireDevice::SendAVCCommand(
+    const vector<uint8_t>  &_cmd,
+    vector<uint8_t>        &result,
+    int                     retry_cnt)
+{
+    retry_cnt = (retry_cnt < 0) ? 2 : retry_cnt;
+
+    result.clear();
+
+    if (!m_priv->handle || (m_node < 0))
+        return false;
+
+    vector<uint8_t> cmd = _cmd;
+    while (cmd.size() & 0x3)
+        cmd.push_back(0x00);
+
+    if (cmd.size() > 4096)
+        return false;
+
+    uint32_t cmdbuf[1024];
+    for (uint i = 0; i < cmd.size(); i+=4)
+        cmdbuf[i>>2] = cmd[i]<<24 | cmd[i+1]<<16 | cmd[i+2]<<8 | cmd[i+3];
+
+    uint result_length = 0;
+
+#ifdef USING_LIBAVC_5_3
+    uint32_t *ret = avc1394_transaction_block2(
+        m_priv->handle, m_node,	cmdbuf, cmd.size() >> 2,
+        &result_length, retry_cnt);
+#else // if !USING_LIBAVC_5_3
+    uint32_t *ret = avc1394_transaction_block(
+        m_priv->handle, m_node,	cmdbuf, cmd.size() >> 2, retry_cnt);
+    result_length = cmd.size() >> 2;
+#endif // !USING_LIBAVC_5_3
+
+    if (!ret)
+        return false;
+
+    for (uint i = 0; i < result_length; i++)
+    {
+        result.push_back((ret[i]>>24) & 0xff);
+        result.push_back((ret[i]>>16) & 0xff);
+        result.push_back((ret[i]>>8)  & 0xff);
+        result.push_back((ret[i])     & 0xff);
+    }
+
+#ifdef USING_LIBAVC_5_3
+    avc1394_transaction_block_close(m_priv->handle);
+#endif // USING_LIBAVC_5_3
+
+    return true;
+}
+
+bool LinuxFirewireDevice::IsPortOpen(void) const
+{
+    QMutexLocker locker(&m_lock);
+
+    return m_priv->handle;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+bool LinuxFirewireDevice::GetPortAndNode(void)
+{
+    m_port = m_node = -1;
+
+    vector<AVCInfo> list = GetSTBList();
+    for (uint i = 0; i < list.size(); i++)
+    {
+        if (list[i].guid == m_guid)
+        {
+            m_port = list[i].port;
+            m_node = list[i].node;
+            break;
+        }
+    }
+
+    bool ok = (m_port >= 0) && (m_node >= 0);
+
+    if (!ok)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to find port and node " +
+                QString("for guid: 0x%1").arg(m_guid,0,16));
+    }
+    else
+    {
+        VERBOSE(VB_RECORD, LOC + QString("port: %1, node: %2")
+                .arg(m_port).arg(m_node));
+    }
+
+    return ok;
+}
+
+bool LinuxFirewireDevice::OpenNode(void)
+{
+    if (m_use_p2p)
+        return OpenP2PNode();
+    else
+        return OpenBroadcastNode();
+}
+
+bool LinuxFirewireDevice::CloseNode(void)
+{ 
+    if (m_priv->is_p2p_node_open)
+        return CloseP2PNode();
+
+    if (m_priv->is_bcast_node_open)
+        return CloseBroadcastNode();
+
+    return true;
+}
+
+bool LinuxFirewireDevice::OpenP2PNode(void)
+{
+    if (m_priv->is_bcast_node_open)
+        return false;
+
+    if (m_priv->is_p2p_node_open)
+        return true;
+
+    VERBOSE(VB_RECORD, LOC + "Opening P2P connection");
+
+    m_priv->channel = m_node;
+    if (iec61883_cmp_create_p2p_output(m_priv->handle, m_node | 0xffc0, 0,
+                                       m_priv->channel, m_speed) != 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create P2P connection");
+
+        m_priv->channel = -1;
+        return false;
+    }
+
+    m_priv->is_p2p_node_open = true;
+
+    return true;
+}
+
+bool LinuxFirewireDevice::CloseP2PNode(void)
+{
+    if (m_priv->is_p2p_node_open && (m_priv->channel >= 0))
+    {
+        VERBOSE(VB_RECORD, LOC + "Closing P2P connection");
+
+        if (m_priv->avstream)
+            CloseAVStream();
+
+        iec61883_cmp_disconnect(m_priv->handle, m_node | 0xffc0, 0,
+                                raw1394_get_local_id(m_priv->handle),
+                                -1, m_priv->channel, 0);
+
+        m_priv->channel = -1;
+        m_priv->is_p2p_node_open = false;
+    }
+
+    return true;
+}
+
+bool LinuxFirewireDevice::OpenBroadcastNode(void)
+{
+    if (m_priv->is_p2p_node_open)
+        return false;
+
+    if (m_priv->is_bcast_node_open)
+        return true;
+
+    m_priv->channel = kBroadcastChannel - m_node;
+
+    VERBOSE(VB_RECORD, LOC + "Opening broadcast connection on " +
+            QString("node %1, channel %2")
+            .arg(m_node).arg(m_priv->channel));
+
+    if (m_priv->avstream)
+        CloseAVStream();
+
+    int err = iec61883_cmp_create_bcast_output(
+        m_priv->handle, m_node | 0xffc0, 0, m_priv->channel, m_speed);
+
+    if (err != 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "Failed to create Broadcast connection");
+
+        m_priv->channel = -1;
+        return false;
+    }
+
+    m_priv->is_bcast_node_open = true;
+
+    return true;
+}
+
+bool LinuxFirewireDevice::CloseBroadcastNode(void)
+{
+    if (m_priv->is_bcast_node_open)
+    {
+        VERBOSE(VB_RECORD, LOC + "Closing broadcast connection");
+
+        m_priv->channel = -1;
+        m_priv->is_bcast_node_open = false;
+    }
+    return true;
+}
+
+bool LinuxFirewireDevice::OpenAVStream(void)
+{
+    VERBOSE(VB_RECORD, LOC + "OpenAVStream");
+
+    if (!IsNodeOpen() && !OpenNode())
+        return false;
+
+    if (m_priv->avstream)
+        return true;
+
+    VERBOSE(VB_RECORD, LOC + "Opening A/V stream object");
+
+    if (!m_priv->handle)
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                "Can not open AVStream without IEEE 1394 Port");
+
+        return false;
+    }
+
+    m_priv->avstream = iec61883_mpeg2_recv_init(
+        m_priv->handle, linux_firewire_device_tspacket_handler, this);
+
+    if (!m_priv->avstream)
+    {
+        VERBOSE(VB_IMPORTANT, LOC + "Unable to open AVStream" + ENO);
+
+        return false;
+    }
+
+    iec61883_mpeg2_set_synch(m_priv->avstream, 1 /* sync on close */);
+
+    if (m_bufsz)
+        SetAVStreamBufferSize(m_bufsz);
+
+    return true;
+}
+
+bool LinuxFirewireDevice::CloseAVStream(void)
+{
+    if (!m_priv->avstream)
+        return true;
+
+    VERBOSE(VB_RECORD, LOC + "Closing A/V stream object");
+
+    while (!m_resetting && m_listeners.size())
+        RemoveListener(m_listeners[m_listeners.size() - 1]);
+
+    if (m_priv->is_streaming)
+        StopStreaming();
+
+    iec61883_mpeg2_close(m_priv->avstream);
+    m_priv->avstream = NULL;
+
+    return true;
+}
+
+void *linux_firewire_device_streaming_thunk(void *param)
+{
+    LinuxFirewireDevice *mon = (LinuxFirewireDevice*) param;
+    mon->RunStreaming();
+    return NULL;
+}
+
+void LinuxFirewireDevice::RunStreaming(void)
+{
+    VERBOSE(VB_RECORD, LOC + "RunStreaming -- start");
+    m_lock.lock();
+    m_priv->is_streaming_running = true;
+
+    uint no_data_cnt = 0;
+    while (m_priv->is_streaming)
+    {
+        no_data_cnt = (LoopIteration(kNoDataTimeout)) ? 0 : no_data_cnt + 1;
+
+        if (m_priv->is_streaming && (no_data_cnt > 30))
+        {
+            no_data_cnt = 0;
+            ResetBus();
+        }
+    }
+
+    m_priv->is_streaming_running = false;
+    m_lock.unlock();
+    VERBOSE(VB_RECORD, LOC + "RunStreaming -- end");
+}
+
+bool LinuxFirewireDevice::StartStreaming(void)
+{
+    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
+    QMutexLocker locker(&m_priv->start_stop_streaming_lock);
+    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- locked");
+
+    if (m_priv->is_streaming)
+        return m_priv->is_streaming;
+
+    assert(!m_priv->is_streaming_running);
+
+    if (!IsAVStreamOpen() && !OpenAVStream())
+        return false;
+
+    if (m_priv->channel < 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no channel");
+        return false;
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- really");
+
+    if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0)
+    {
+        m_priv->is_streaming = true;
+
+        pthread_create(&m_priv->streaming_thread, NULL,
+                       linux_firewire_device_streaming_thunk, this);
+
+        m_lock.unlock();
+        while (!m_priv->is_streaming_running)
+            usleep(5000);
+        m_lock.lock();
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming " + ENO);
+    }
+
+    return m_priv->is_streaming;
+}
+
+bool LinuxFirewireDevice::StopStreaming(void)
+{
+    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
+    QMutexLocker locker(&m_priv->start_stop_streaming_lock);
+    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- locked");
+
+    if (m_priv->is_streaming)
+    {
+        VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really");
+
+        m_priv->is_streaming = false;
+
+        VERBOSE(VB_RECORD, LOC + "Waiting for A/V streaming to stop");
+        while (m_priv->is_streaming_running)
+        {
+            m_lock.unlock();
+            usleep(5000);
+            m_lock.lock();
+        }
+
+        VERBOSE(VB_RECORD, LOC + "Joining A/V streaming thread");
+        pthread_join(m_priv->streaming_thread, NULL);
+
+        iec61883_mpeg2_recv_stop(m_priv->avstream);
+
+        raw1394_iso_recv_flush(m_priv->handle);
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
+
+    return true;
+}
+
+bool LinuxFirewireDevice::StopStreamingLater(void)
+{
+    // TODO
+    return true;
+}
+
+bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes)
+{
+    if (!m_priv->avstream)
+        return false;
+
+    // Set buffered packets size
+    uint   buffer_size      = max(size_in_bytes, 50 * TSPacket::SIZE);
+    size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets);
+
+    iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets);
+
+    VERBOSE(VB_IMPORTANT, LOC +
+            QString("Buffered packets %1 (%2 KB)")
+            .arg(buffered_packets).arg(buffered_packets * 4));
+
+    return true;
+}
+
+bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed)
+{
+    if (!m_priv->avstream)
+        return false;
+
+    uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream);
+
+    if (curspeed == speed)
+    {
+        m_speed = speed;
+        return true;
+    }
+
+    VERBOSE(VB_RECORD, LOC +
+            QString("Changing Speed %1 -> %2")
+            .arg(speed_to_string(curspeed))
+            .arg(speed_to_string(m_speed)));
+
+    iec61883_mpeg2_set_speed(m_priv->avstream, speed);
+
+    if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream))
+    {
+        m_speed = speed;
+        return true;
+    }
+
+    VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set firewire speed.");
+
+    return false;
+}
+
+bool LinuxFirewireDevice::IsNodeOpen(void) const
+{
+    return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open;
+}
+
+bool LinuxFirewireDevice::IsAVStreamOpen(void) const
+{
+    return m_priv->avstream;
+}
+
+bool LinuxFirewireDevice::ResetBus(void)
+{
+    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- begin");
+
+    bool ok = (raw1394_reset_bus_new(m_priv->handle, RAW1394_LONG_RESET) == 0);
+    if (!ok)
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed" + ENO);
+
+    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end");
+
+    return ok;
+}
+
+bool LinuxFirewireDevice::LoopIteration(uint timeout_in_msec)
+{
+    if (m_resetting)
+        return true;
+
+    int fwfd = raw1394_get_fd(m_priv->handle);
+    if (fwfd < 0)
+        return false;
+
+    struct timeval tv;
+    fd_set rfds;
+
+    FD_ZERO(&rfds);
+    FD_SET(fwfd, &rfds);
+
+    tv.tv_sec  = timeout_in_msec / 1000;
+    tv.tv_usec = (timeout_in_msec % 1000) * 1000;
+
+    m_lock.unlock();
+    if (select(fwfd + 1, &rfds, NULL, NULL, &tv) <= 0)
+    {
+        m_lock.lock();
+        VERBOSE(VB_IMPORTANT, LOC + QString("No Input in %1 msec...")
+                .arg(timeout_in_msec));
+
+        return false;
+    }
+    m_lock.lock();
+
+    int ret = raw1394_loop_iterate(m_priv->handle);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "libraw1394_loop_iterate() " + 
+                QString("returned %1").arg(ret));
+
+        return false;
+    }
+
+    return true;
+}
+
+void LinuxFirewireDevice::PrintDropped(uint dropped_packets)
+{
+    if (dropped_packets == 1)
+    {
+        VERBOSE(VB_RECORD, LOC_ERR + "Dropped a TS packet");
+    }
+    else if (dropped_packets > 1)
+    {
+        VERBOSE(VB_RECORD, LOC_ERR + 
+                QString("Dropped %1 TS packets").arg(dropped_packets));
+    }
+}
+
+vector<AVCInfo> LinuxFirewireDevice::GetSTBList(void)
+{
+    vector<AVCInfo> list;
+
+    raw1394handle_t handle = raw1394_new_handle();
+    if (!handle)
+    {
+        VERBOSE(VB_IMPORTANT, "Couldn't get handle" + ENO);
+        return list;
+    }
+
+    struct raw1394_portinfo port_info[16];
+    int numcards = raw1394_get_port_info(handle, port_info, 16);
+    if (numcards < 1)
+    {
+        raw1394_destroy_handle(handle);
+        return list;
+    }
+
+    for (int port = 0; port < numcards; port++)
+    {
+        if (raw1394_set_port(handle, port) < 0)
+        {
+            VERBOSE(VB_IMPORTANT, "Couldn't set port to " << port);
+            continue;
+        }
+
+        for (int node = 0; node < raw1394_get_nodecount(handle); node++)
+        {
+            AVCInfo info;
+
+            info.guid = get_guid(handle, 0xffc0 | node);
+
+            rom1394_directory dir;
+            if (rom1394_get_directory(handle, node, &dir) < 0)
+            {
+                continue;
+            }
+            info.port     = port;
+            info.node     = node;
+            info.vendorid = dir.vendor_id;
+            info.modelid  = dir.model_id;
+            info.specid   = dir.unit_spec_id;
+            info.firmware_revision = dir.unit_sw_version;
+            info.product_name = QString("%1").arg(dir.label);
+
+            uint8_t unit_table[32];
+            
+            if (avc1394_subunit_info(handle, node, (uint32_t*)unit_table) < 0)
+                memset(unit_table, 0xff, sizeof(unit_table));
+
+            if (IsSubunitType(unit_table, kAVCSubunitTypeTuner) &&
+                IsSubunitType(unit_table, kAVCSubunitTypePanel))
+            {
+                list.push_back(info);
+            }
+        }
+
+        raw1394_destroy_handle(handle);
+
+        handle = raw1394_new_handle();
+        if (!handle)
+        {
+            VERBOSE(VB_IMPORTANT, "Couldn't get handle "
+                    "(after setting port "<<port<<")" + ENO);
+            handle = NULL;
+            break;
+        }
+
+        numcards = raw1394_get_port_info(handle, port_info, 16);
+    }
+
+    if (handle)
+        raw1394_destroy_handle(handle);
+
+    return list;
+}
+
+int linux_firewire_device_tspacket_handler(
+    unsigned char *tspacket, int len, uint dropped, void *callback_data)
+{
+    LinuxFirewireDevice *fw = (LinuxFirewireDevice*) callback_data;
+    if (!fw)
+        return 0;
+
+    if (dropped)
+        fw->PrintDropped(dropped);
+
+    if (len > 0)
+        fw->BroadcastToListeners(tspacket, len);
+
+    return 1;
+}
+
+static QString speed_to_string(uint speed)
+{
+    if (speed > 3)
+        return QString("Invalid Speed (%1)").arg(speed);
+
+    static const uint speeds[] = { 100, 200, 400, 800 };
+    return QString("%1Mbps").arg(speeds[speed]);
+}
+
+static int linux_firewire_device_bus_reset_handler(
+    raw1394handle_t handle, unsigned int generation)
+{
+    QMutexLocker locker(&LFDPriv::s_lock);
+
+    handle_to_lfd_t::iterator it = LFDPriv::s_handle_info.find(handle);
+
+    if (it != LFDPriv::s_handle_info.end())
+        (*it)->HandleBusReset(generation);
+
+    return 0;
+}
+
+// get_guid copied from plugreport, Copyright 2002-2004 Dan Dennedy GPL v2+
+#define PLUGREPORT_GUID_HI 0x0C
+#define PLUGREPORT_GUID_LO 0x10
+static uint64_t get_guid(raw1394handle_t handle, nodeid_t node)
+{
+    uint32_t quadlet;
+    uint64_t offset;
+    uint64_t guid = 0;
+
+    offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_HI;
+    raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
+    quadlet = htonl(quadlet);
+    guid = quadlet;
+    guid <<= 32;
+    offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_LO;
+    raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
+    quadlet = htonl(quadlet);
+    guid += quadlet;
+
+    return guid;
+}
Index: programs/mythbackend/backendutil.cpp
===================================================================
--- programs/mythbackend/backendutil.cpp	(revision 12321)
+++ programs/mythbackend/backendutil.cpp	(working copy)
@@ -2,6 +2,8 @@
 #ifdef CONFIG_DARWIN
 #include <sys/param.h>
 #include <sys/mount.h>
+unsigned long long int abs(long long int v)
+    { return (unsigned long long int) ((v < 0) ? -v : v); }
 #elif __linux__
 #include <sys/vfs.h>
 #endif
