Index: libs/libmythtv/firewirechannel.cpp
===================================================================
--- libs/libmythtv/firewirechannel.cpp	(revision 12256)
+++ libs/libmythtv/firewirechannel.cpp	(working copy)
@@ -1,314 +1,178 @@
 /**
  *  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(
+    const FireWireDBOptions &firewire_opts, TVRec *parent) :
+    DTVChannel(parent),
+    fw_opts(firewire_opts),
+    device(NULL),
+    current_channel(0),
+    is_port_open(false)
+{
+#ifdef USING_LINUX_FIREWIRE
+    device = new LinuxFirewireDevice(
+        fw_opts.port, fw_opts.node, fw_opts.speed,
+        LinuxFirewireDevice::kConnectionP2P ==
+        (uint) fw_opts.connection);
+#elif USING_OSX_FIREWIRE
+    device = new DarwinFirewireDevice();
 #endif
+}
 
-#ifndef AVC1394_PANEL_OPERATION_0
-#define AVC1394_PANEL_OPERATION_0              0x000000020
-#endif
+bool FirewireChannel::SetChannelByString(const QString &chan)
+{
+    inputs[currentInputID]->startChanNum = chan; 
+    curchannelname = chan;
 
-#define DCT6200_CMD0  (AVC1394_CTYPE_CONTROL | \
-                       AVC1394_SUBUNIT_TYPE_PANEL | \
-                       AVC1394_SUBUNIT_ID_0 | \
-                       AVC1394_PANEL_COMMAND_PASS_THROUGH | \
-                       AVC1394_PANEL_OPERATION_0)
+    InputMap::const_iterator it = inputs.find(currentInputID);
 
-// SA3250HD defines
-#define AVC1394_SA3250_OPERAND_KEY_PRESS	0xE7
-#define AVC1394_SA3250_OPERAND_KEY_RELEASE	0x67
+    if (!(*it)->externalChanger.isEmpty()) 
+        return ChangeExternalChannel(chan);
 
-#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
+    return isopen && SetChannelByNumber(chan.toInt());
+}
 
-// 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 FirewireChannel::Open(void)
+{
+    if (!InitializeInputs()) 
+        return false; 
 
-#define STB_POWER_ON      (AVC1394_CTYPE_CONTROL | \
-                           AVC1394_SUBUNIT_TYPE_UNIT | \
-                           AVC1394_SUBUNIT_ID_IGNORE | \
-                           AVC1394_COMMAND_POWER | \
-                           AVC1394_CMD_OPERAND_POWER_ON)
+    InputMap::const_iterator it = inputs.find(currentInputID); 
+    if (!(*it)->externalChanger.isEmpty()) 
+        return true;
 
-static bool is_supported(const QString &model)
-{
-    return ((model == "DCT-6200") ||
-            (model == "SA3250HD") ||
-	    (model == "SA4200HD"));
-}
+    if (!isopen)
+        isopen = OpenFirewire(); 
 
-FirewireChannel::FirewireChannel(FireWireDBOptions firewire_opts,
-                                 TVRec *parent)
-    : FirewireChannelBase(parent), fw_opts(firewire_opts), fwhandle(NULL)
-{
+    return isopen; 
 }
 
-FirewireChannel::~FirewireChannel(void)
+void FirewireChannel::Close(void)
 {
-    Close();
+    if (isopen)
+    {
+        CloseFirewire();
+        isopen = false;
+    }
 }
-
-bool FirewireChannel::SetChannelByNumber(int channel)
+    
+bool FirewireChannel::OpenFirewire(void)
 {
-    // Change channel using internal changer
+    if (is_port_open)
+        return true;
 
-    if (!is_supported(fw_opts.model))
+    if (!FirewireDevice::IsSTBSupported(fw_opts.model))
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR +
                 QString("Model: '%1' ").arg(fw_opts.model) +
                 "is not supported by internal channel changer.");
+
         return false;
     }
 
-    int dig[3];
-    dig[0] = (channel % 1000) / 100;
-    dig[1] = (channel % 100)  / 10;
-    dig[2] = (channel % 10);
+    if (!device)
+        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));
+    if (!device->OpenPort())
+        return false;
 
-        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")
+    if (!device->IsSTB())
     {
-        dig[0] |= 0x30;
-        dig[1] |= 0x30;
-        dig[2] |= 0x30;
+        device->ClosePort();
+        return false;
+    }
 
-        quadlet_t cmd[3] =
-        {
-            SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 
-            SA3250_CMD1 | (dig[2] << 16) | (dig[1] << 8) | dig[0],
-            SA3250_CMD2,
-        };
+    is_port_open = true;
 
-        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 true;
+}
 
-        if(!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
-        {
-            VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
-            return false;
-        }
+void FirewireChannel::CloseFirewire(void)
+{
+    if (!is_port_open)
+        return;
 
-        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;
+    device->ClosePort();
+    is_port_open = 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));
+bool FirewireChannel::SwitchToInput(const QString &input,
+                                        const QString &chan)
+{
+    int inputNum = GetInputByName(input); 
+    if (inputNum < 0) 
+        return false;
 
-        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")
-    {
-        quadlet_t cmd[3] =
-        {
-            SA3250_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
-            SA3250_CMD1 | (channel << 8),
-            SA3250_CMD2,
-        };
+    return SetChannelByString(chan);
+}
 
-        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));
+QString FirewireChannel::GetDevice(void) const
+{
+    return QString("%1:%2").arg(fw_opts.port).arg(fw_opts.node);
+}
 
-        if (!avc1394_transaction_block(fwhandle, fw_opts.node, cmd, 3, 1))
-        {
-            VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
-            return false;
-        }
-    }
+bool FirewireChannel::SetPowerState(bool on)
+{
+    return device->SetPowerState(on);
+}
 
-    return true;
+FirewireDevice::PowerState FirewireChannel::GetPowerState(void) const
+{
+    return device->GetPowerState();
 }
 
-bool FirewireChannel::OpenFirewire(void)
+bool FirewireChannel::Retune(void)
 {
-    if (!is_supported(fw_opts.model))
+    VERBOSE(VB_CHANNEL, LOC + "Retune()");
+
+    if (FirewireDevice::kAVCPowerOff == GetPowerState())
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR +
-                QString("Model: '%1' ").arg(fw_opts.model) +
-                "is not supported by internal channel changer.");
-        return false;
-    }
+                "STB is turned off, must be on to retune.");
 
-    // 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;
     }
 
-    VERBOSE(VB_CHANNEL, LOC + "Allocated raw1394 handle " +
-            QString("for port %1").arg(fw_opts.port));
+    if (current_channel)
+        return SetChannelByNumber(current_channel);
 
-    // 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;
-    }
+    return false;
+}
 
-    if (!avc1394_check_subunit_type(fwhandle, fw_opts.node, 
-                                    AVC1394_SUBUNIT_TYPE_PANEL))
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("node %1 is not subunit "
-                "type panel.").arg(fw_opts.node));
-        CloseFirewire();
-        return false;
-    }
+bool FirewireChannel::SetChannelByNumber(int channel)
+{
+    current_channel = channel;
 
-    // check power, power on if off
-    if (GetPowerState() == Off)
+    if (FirewireDevice::kAVCPowerOff == GetPowerState())
     {
-        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];
+        VERBOSE(VB_IMPORTANT, LOC_WARN +
+                "STB is turned off, must be on to set 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;
-        }
+        SetSIStandard("mpeg");
+        SetCachedATSCInfo(QString("%1-1").arg(channel));
+
+        return true; // signal monitor will call retune later...
     }
-    return true;
-}
 
-void FirewireChannel::CloseFirewire(void)
-{
-    VERBOSE(VB_CHANNEL, LOC + "Releasing raw1394 handle");
-    raw1394_destroy_handle(fwhandle);
-}
+    if (!device->SetChannel(fw_opts.model, channel))
+        return false;
 
-FirewireChannel::PowerState FirewireChannel::GetPowerState(void)
-{
-    quadlet_t *rval, response, cmd = STB_POWER_STATE;
+    SetSIStandard("mpeg");
+    SetCachedATSCInfo(QString("%1-1").arg(channel));
 
-    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)
-    {
-        response = rval[0];
-
-        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;
-        }
-    }
-    VERBOSE(VB_CHANNEL, LOC + "Failed to get STB Power State");
-    return Failed;
+    return true;
 }
Index: libs/libmythtv/firewirerecorderbase.h
===================================================================
--- libs/libmythtv/firewirerecorderbase.h	(revision 12256)
+++ 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 12256)
+++ 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,82 @@
+/**
+ *  FirewireDevice
+ *  Copyright (c) 2005 by Jim Westfall
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// MythTV headers
+#include "firewiredevice.h"
+#include "mythcontext.h"
+#include "pespacket.h"
+
+#define LOC      QString("FireDev(): ")
+#define LOC_WARN QString("FireDev(), Warning: ")
+#define LOC_ERR  QString("FireDev(), Error: ")
+
+FirewireDevice::FirewireDevice() :
+    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());
+}
+
+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");
+    }
+}
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 12256)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -377,20 +377,22 @@
     }
 
     # 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
+            SOURCES += darwinfirewiredevice.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
Index: libs/libmythtv/darwinfirewirerecorder.cpp
===================================================================
--- libs/libmythtv/darwinfirewirerecorder.cpp	(revision 12256)
+++ 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/dbcheck.cpp
===================================================================
--- libs/libmythtv/dbcheck.cpp	(revision 12256)
+++ 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 = "1172";
+const QString currentDatabaseVersion = "1173";
 
 static bool UpdateDBVersionNumber(const QString &newnumber);
 static bool performActualUpdate(const QString updates[], QString version,
@@ -2772,6 +2772,17 @@
             return false;
     }
 
+    if (dbver == "1172")
+    {
+        // Add Firewire and DBox2 default recording profiles..
+        const QString updates[] = {
+"UPDATE capturecard SET channel_timeout = 9000 WHERE cardtype = 'FIREWIRE';",
+""
+};
+        if (!performActualUpdate(updates, "1173", 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
Index: libs/libmythtv/signalmonitor.h
===================================================================
--- libs/libmythtv/signalmonitor.h	(revision 12256)
+++ 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,468 @@
+/**
+ *  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.
+ */
+
+#undef always_inline
+#include <AVCVideoServices/AVCVideoServices.h>
+
+#include "darwinfirewiredevice.h"
+#include "mythcontext.h"
+
+#define LOC      QString("DFireDev(): ")
+#define LOC_WARN QString("DFireDev(), Warning: ")
+#define LOC_ERR  QString("DFireDev(), Error: ")
+
+namespace AVS
+{
+    class AVCDeviceController;
+    class AVCDevice;
+    class AVCDeviceStream;
+    class StringLogger;
+}
+
+static bool dfd_find_panel_device(AVS::AVCDevice *d);
+static bool dfd_find_capture_device(AVS::AVCDevice *d);
+static AVS::AVCDevice *dfd_select_device(AVS::AVCDeviceController*,
+                                         bool (*)(AVS::AVCDevice*));
+
+static void dfd_log_message(char *pString);
+static void dfd_err_message(uint32_t msg, uint32_t param1,
+                            uint32_t param2, void *callback_data);
+
+class DFDPriv
+{
+  public:
+    DFDPriv() :
+        avc_device_controller(NULL), avc_device(NULL),
+        avstream(NULL), message_log(NULL), is_streaming(false) { }
+
+    AVS::AVCDeviceController *avc_device_controller;
+    AVS::AVCDevice           *avc_device;
+    AVS::AVCDeviceStream     *avstream;
+    AVS::StringLogger        *message_log;
+    bool                      is_streaming;
+};
+
+DarwinFirewireDevice::DarwinFirewireDevice() : 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;
+    }
+}
+
+bool DarwinFirewireDevice::OpenPort(void)
+{
+    QMutexLocker locker(&m_lock);
+
+    VERBOSE(VB_RECORD, LOC + "OpenPort()");
+
+    m_open_port_cnt++;
+
+    if (m_priv->avc_device)
+        return true;
+
+    int err = AVS::CreateAVCDeviceController(&m_priv->avc_device_controller);
+    if (err)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to open device controller: " +
+                QString("%1").arg(err,0,16));
+
+        return false;
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Opening AVC Device");
+
+    m_priv->avc_device = dfd_select_device(
+        m_priv->avc_device_controller, dfd_find_panel_device);
+
+    if (!m_priv->avc_device)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "Unable to find an attached "
+                "MPEG2 device that supports channel changes");
+
+        AVS::DestroyAVCDeviceController(m_priv->avc_device_controller);
+        m_priv->avc_device_controller = NULL;
+
+        return false;
+    }
+
+    err = m_priv->avc_device->openDevice();
+
+    if (err)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("Couldn't open tuner device: %1").arg(err,0,16));
+
+        AVS::DestroyAVCDeviceController(m_priv->avc_device_controller);
+        m_priv->avc_device_controller = NULL;
+
+        return false;
+    }
+
+    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 (m_priv->avc_device)
+    {
+        VERBOSE(VB_RECORD, LOC + "Closing AVC Device");
+
+        m_priv->avc_device->closeDevice();
+
+        //AVS::DestroyAVCDevice(m_priv->avc_device);
+        m_priv->avc_device = NULL;
+    }
+
+    return true;
+}
+
+bool DarwinFirewireDevice::OpenAVStream(void)
+{
+    VERBOSE(VB_RECORD, LOC + "Creating logger object");
+
+    m_priv->message_log = new AVS::StringLogger(dfd_log_message);
+    if (!m_priv->message_log)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't create logger");
+        return false;
+    }
+
+    // Plug number.  Why is zero always OK?  I don't know, but that's
+    // what Apple's examples do.
+    uint plug_num = 0;
+
+    // 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.
+    uint recv_segments = 2 * AVS::kNumReceiveSegments;
+
+    // This not only builds an MPEG2Receiver object
+    // but also starts dedicated real-time threads.
+    m_priv->avstream = m_priv->avc_device->CreateMPEGReceiverForDevicePlug(
+        plug_num, dfd_tspacket_handler, this, dfd_err_message, this,
+        m_priv->message_log, AVS::kCyclesPerReceiveSegment, recv_segments);
+
+    if (!m_priv->avstream)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "Couldn't create MPEG-2 device stream");
+
+        CloseAVStream();
+
+        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
+    m_priv->avstream->pMPEGReceiver->registerNoDataNotificationCallback(
+        dfd_no_data_notification, this, 50 /* msec */);
+
+    return true;
+}
+
+bool DarwinFirewireDevice::CloseAVStream(void)
+{
+    if (m_priv->avstream)
+    {
+        StopStreaming();
+        VERBOSE(VB_RECORD, LOC + "Destroying device stream");
+        m_priv->avc_device->DestroyAVCDeviceStream(m_priv->avstream);
+        m_priv->avstream = NULL;
+    }
+
+    if (m_priv->message_log)
+    {
+        delete m_priv->message_log;
+        m_priv->message_log = NULL;
+    }
+
+    return true;
+}
+
+bool DarwinFirewireDevice::StartStreaming(void)
+{
+    if (m_priv->is_streaming)
+        return m_priv->is_streaming;
+
+    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming");
+
+    if (!m_priv->avstream)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no A/V obj");
+        return false;
+    }
+
+    m_priv->avc_device->StartAVCDeviceStream(m_priv->avstream);
+    m_priv->is_streaming = true;
+
+    return m_priv->is_streaming;
+}
+
+bool DarwinFirewireDevice::StopStreaming(void)
+{
+    VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming");
+
+    if (m_priv->is_streaming)
+    {
+        m_priv->is_streaming = false;
+        m_priv->avc_device->StopAVCDeviceStream(m_priv->avstream);
+    }
+
+    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
+
+    return true;
+}
+
+bool DarwinFirewireDevice::SetChannel(const QString &panel_model, uint channel)
+{
+    QMutexLocker locker(&m_lock);
+
+    (void) panel_model;
+
+    AVS::PanelSubunitController panel(m_priv->avc_device);
+
+    int err = panel.Tune(channel);
+    if (err != kIOReturnSuccess)
+    {
+        VERBOSE(VB_GENERAL, LOC_ERR + "Tuning failed: " +
+                QString("0x%1").arg(err,0,16));
+
+        return false;
+    }
+
+    return true;
+}
+
+bool DarwinFirewireDevice::SetPowerState(bool on)
+{
+    QMutexLocker locker(&m_lock);
+
+    if (on)
+        m_priv->avc_device->SetPowerState(kAVCPowerStateOn);
+    else
+        m_priv->avc_device->SetPowerState(kAVCPowerStateOff);
+
+    return true;
+}
+
+FirewireDevice::PowerState DarwinFirewireDevice::GetPowerState(void)
+{
+    QMutexLocker locker(&m_lock);
+
+    uint8_t power_state;
+
+    int err = m_priv->avc_device->GetPowerState(&power_state);
+
+    if (err != kIOReturnSuccess)
+        return FirewireDevice::kAVCPowerQueryFailed;
+    else if (kAVCPowerStateOff == power_state)
+        return FirewireDevice::kAVCPowerOff;
+    else if (kAVCPowerStateOn == power_state)
+        return FirewireDevice::kAVCPowerOn;
+    else
+        return FirewireDevice::kAVCPowerUnknown;
+}
+
+bool DarwinFirewireDevice::IsPortOpen(void) const
+{
+    QMutexLocker locker(&m_lock);
+
+    return m_priv->avc_device;
+}
+
+bool DarwinFirewireDevice::IsTuner(void) const
+{
+    return IsPortOpen();
+}
+
+bool DarwinFirewireDevice::IsPanel(void) const
+{
+    return IsPortOpen();
+}
+
+bool DarwinFirewireDevice::IsSTB(void) const
+{
+    return IsPortOpen();
+}
+
+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);
+
+    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 DarwinFirewireDevice::no_data(void)
+{
+    VERBOSE(VB_IMPORTANT, LOC_WARN + "No Input in 50 msecs");
+}
+
+// Various message callbacks.
+int dfd_no_data_notification(void *callback_data)
+{
+    DarwinFirewireDevice *fw =
+        static_cast<DarwinFirewireDevice*>(callback_data);
+
+    fw->no_data();
+
+    return 0;
+}
+
+int dfd_tspacket_handler(uint32_t 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], 1);
+
+    return 0;
+}
+
+// For the time being, the DarwinFireWireRecorder doesn't
+// handle DV 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.
+static bool dfd_find_panel_device(AVS::AVCDevice *d)
+{
+    return d->isAttached && d->hasMonitorOrTunerSubunit && !d->isDVDevice;
+}
+
+// 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.
+static bool dfd_find_capture_device(AVS::AVCDevice *d)
+{
+    return d->isAttached && !d->isDVDevice;
+}
+
+// TODO This needs to be worked on so that we can handle multiple STBs.
+static AVS::AVCDevice *dfd_select_device(AVS::AVCDeviceController *controller,
+                                         bool (*filter)(AVS::AVCDevice*))
+{
+    VERBOSE(VB_RECORD, "dfd_select_device()");
+
+    uint cnt = CFArrayGetCount(controller->avcDeviceArray);
+    for (uint i = 0; i < cnt; i++)
+    {
+        AVS::AVCDevice *dev = (AVS::AVCDevice*)
+            CFArrayGetValueAtIndex(controller->avcDeviceArray, i);
+
+        VERBOSE(VB_RECORD,
+                QString("dfd_select_device: "
+                        "%1, format: %2, attached: %3, type: %4")
+                .arg(dev->deviceName)
+                .arg(dev->isDVDevice ? "DV" :
+                     dev->isMPEGDevice ? "MPEG2-TS" : "unknown")
+                .arg(dev->isAttached ? "yes" : "no")
+                .arg(dev->hasTapeSubunit ? "tape" :
+                     dev->hasMonitorOrTunerSubunit ? "tuner" : "unknown"));
+
+        if (filter(dev))
+        {
+            VERBOSE(VB_RECORD, "dfd_select_device: FOUND");
+            return dev;
+        }
+    }
+
+    VERBOSE(VB_RECORD, "dfd_select_device: NOT FOUND");
+
+    return 0;
+}
+
+#define AVC_MSG_LOC     QString("Firewire MPEG2Receiver: ")
+#define AVC_MSG_LOC_ERR QString("Firewire MPEG2Receiver, Error: ")
+static void dfd_log_message(char *pString)
+{
+    VERBOSE(VB_RECORD, AVC_MSG_LOC + QString("Log: %1").arg(pString));
+}
+
+static void dfd_err_message(
+    uint32_t msg, uint32_t param1, uint32_t param2, void *callback_data)
+{
+    (void) callback_data;
+
+    if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
+    {
+        VERBOSE(VB_RECORD, AVC_MSG_LOC +
+                QString("Allocated channel: %1, speed %2")
+                .arg(param2).arg(param1));
+    }
+    else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
+        VERBOSE(VB_IMPORTANT, AVC_MSG_LOC_ERR + "DCL Overrun");
+    else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
+        VERBOSE(VB_IMPORTANT, AVC_MSG_LOC_ERR + "Received Bad Packet");
+    else
+        VERBOSE(VB_RECORD, AVC_MSG_LOC + QString("Message: %1").arg(msg));
+}
+#undef AVC_MSG_LOC
+#undef AVC_MSG_LOC_ERR
Index: libs/libmythtv/firewirerecorderbase.cpp
===================================================================
--- libs/libmythtv/firewirerecorderbase.cpp	(revision 12256)
+++ 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 12256)
+++ 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: ")
+#define LOC_ERR QString("FireRecBase, Error: ")
 
-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 12256)
+++ 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/darwinfirewiredevice.h
===================================================================
--- libs/libmythtv/darwinfirewiredevice.h	(revision 0)
+++ libs/libmythtv/darwinfirewiredevice.h	(revision 0)
@@ -0,0 +1,52 @@
+#ifndef _DARWIN_FIREWIRE_DEVICE_H_
+#define _DARWIN_FIREWIRE_DEVICE_H_
+
+#include "firewiredevice.h"
+
+class DFDPriv;
+
+class DarwinFirewireDevice : public FirewireDevice
+{
+    friend int dfd_no_data_notification(void *cb_data);
+    friend int dfd_tspacket_handler(
+        uint32_t tsPacketCount, uint32_t **ppBuf, void *callback_data);
+
+  public:
+    DarwinFirewireDevice();
+    ~DarwinFirewireDevice();
+
+    virtual bool OpenPort(void);
+    virtual bool ClosePort(void);
+
+    virtual void AddListener(TSDataListener*);
+    virtual void RemoveListener(TSDataListener*);
+
+    // Sets
+    virtual bool SetPowerState(bool on);
+    virtual bool SetChannel(const QString &panel_model, uint channel);
+
+    // Gets
+    virtual bool IsPortOpen(void) const;
+    virtual bool IsTuner(void) const;
+    virtual bool IsPanel(void) const;
+    virtual bool IsSTB(void) const;
+
+    // non-const Gets
+    virtual PowerState GetPowerState(void);
+
+    void no_data(void);
+
+  private:
+    bool OpenAVStream(void);
+    bool CloseAVStream(void);
+
+    bool StartStreaming(void);
+    bool StopStreaming(void);
+
+    void BroadcastToListeners(const unsigned char *data, uint dataSize);
+
+  private:
+    DFDPriv *m_priv;
+};
+
+#endif // _DARWIN_FIREWIRE_DEVICE_H_
Index: libs/libmythtv/darwinfirewirechannel.cpp
===================================================================
--- libs/libmythtv/darwinfirewirechannel.cpp	(revision 12256)
+++ 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/mpeg/streamlisteners.h
===================================================================
--- libs/libmythtv/mpeg/streamlisteners.h	(revision 12256)
+++ 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 12256)
+++ 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 12256)
+++ 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 12256)
+++ 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/firewirechannel.h
===================================================================
--- libs/libmythtv/firewirechannel.h	(revision 12256)
+++ libs/libmythtv/firewirechannel.h	(working copy)
@@ -1,50 +1,60 @@
 /**
  *  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(const FireWireDBOptions &firewire_opts, TVRec *parent);
 
-    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)
+        { (void)newcapchannel; (void)setstarting; return false; }
 
-    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; }
 
+  protected:
+    FirewireChannel(TVRec *parent) :
+        DTVChannel(parent), isopen(false) { }
+    ~FirewireChannel() { Close(); }
+
   private:
+    virtual bool OpenFirewire(void);
+    virtual void CloseFirewire(void);
+
+  protected:
+    bool               isopen;
     FireWireDBOptions  fw_opts;
-    nodeid_t           fwnode;
-    raw1394handle_t    fwhandle;
+    FirewireDevice    *device;
+    uint               current_channel;
+    bool               is_port_open;
 };
 
-#endif
+#endif // _FIREWIRECHANNEL_H_
Index: libs/libmythtv/videosource.cpp
===================================================================
--- libs/libmythtv/videosource.cpp	(revision 12256)
+++ libs/libmythtv/videosource.cpp	(working copy)
@@ -1031,8 +1031,14 @@
         hg1->addChild(new FirewireNode(parent));
         hg1->addChild(new FirewireSpeed(parent));
         addChild(hg1);
-        addChild(new FirewireInput(parent));
+
+        FirewireInput *defaultinput = new FirewireInput(parent);
+        addChild(defaultinput);
+        defaultinput->setVisible(false);
+
+        addChild(new ChannelTimeout(parent, 9000));
     };
+
   private:
     CaptureCard &parent;
 };
@@ -1186,6 +1192,9 @@
         HDHRCardInput *defaultinput = new HDHRCardInput(parent);
         addChild(defaultinput);
         defaultinput->setVisible(false);
+
+        addChild(new SignalTimeout(parent, 1000));
+        addChild(new ChannelTimeout(parent, 3000));
     };
 
   private:
Index: libs/libmythtv/selectavcdevice.cpp
===================================================================
--- libs/libmythtv/selectavcdevice.cpp	(revision 12256)
+++ 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 12256)
+++ 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,92 @@
+/**
+ *  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(uint port, uint node, uint speed, bool use_p2p,
+                        uint av_buffer_size_in_bytes = 0);
+    ~LinuxFirewireDevice();
+
+    virtual bool OpenPort(void);
+    virtual bool ClosePort(void);
+
+    virtual void AddListener(TSDataListener*);
+    virtual void RemoveListener(TSDataListener*);
+
+    // Sets
+    virtual bool SetPowerState(bool on);
+    virtual bool SetChannel(const QString &panel_model, uint channel);
+
+    // Gets
+    virtual bool IsPortOpen(void) const;
+    virtual bool IsTuner(void) const;
+    virtual bool IsPanel(void) const;
+    virtual bool IsSTB(void) const;
+
+    // non-const Gets
+    virtual PowerState GetPowerState(void);
+
+    // Constants
+    static const uint kBroadcastChannel;
+    static const uint kConnectionP2P;
+    static const uint kConnectionBroadcast;
+    static const uint kMaxBufferedPackets;
+
+  private:
+    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);
+    void BroadcastToListeners(const unsigned char *data, uint dataSize);
+
+    bool SetAVStreamBufferSize(uint size_in_bytes);
+    bool SetAVStreamSpeed(uint speed);
+
+    bool IsNodeOpen(void) const;
+    bool IsAVStreamOpen(void) const;
+    bool IsSubunitType(uint subunit_type) const;
+
+  private:
+    uint                     m_port;
+    uint                     m_node;
+    uint                     m_speed;
+    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 12256)
+++ 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
         if (!channel->Open())
             return false;
         InitChannel(genOpt.defaultinput, startchannel);
@@ -831,16 +819,15 @@
     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());
+        if (recorder)
+        {
+            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 // USING_FIREWIRE
     }
     else if (genOpt.cardtype == "DBOX2")
@@ -1114,6 +1101,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
Index: libs/libmythtv/tv_rec.h
===================================================================
--- libs/libmythtv/tv_rec.h	(revision 12256)
+++ libs/libmythtv/tv_rec.h	(working copy)
@@ -35,6 +35,7 @@
 class DBox2Channel;
 class DTVChannel;
 class DVBChannel;
+class FirewireChannel;
 class Channel;
 class HDHRChannel;
 
@@ -261,6 +262,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 12256)
+++ 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,88 @@
+/**
+ *  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 FirewireDevice
+{
+  public:
+    // Public enums
+    typedef enum
+    {
+        kAVCPowerOn,
+        kAVCPowerOff,
+        kAVCPowerUnknown,
+        kAVCPowerQueryFailed,
+    } PowerState;
+
+    FirewireDevice();
+    virtual ~FirewireDevice() { }
+
+    virtual bool OpenPort(void) = 0;
+    virtual bool ClosePort(void) = 0;
+
+    virtual void AddListener(TSDataListener*);
+    virtual void RemoveListener(TSDataListener*);
+
+    // Sets
+    virtual bool SetPowerState(bool on) = 0;
+    virtual bool SetChannel(const QString &panel_model, uint channel) = 0;
+
+    // Gets
+    virtual bool IsPortOpen(void) const = 0;
+    virtual bool IsTuner(void) const = 0;
+    virtual bool IsPanel(void) const = 0;
+    virtual bool IsSTB(void) const = 0;
+    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
+
+    // non-const Gets
+    virtual PowerState GetPowerState(void) = 0;
+
+    // Statics
+    static inline bool IsSTBSupported(const QString &model);
+
+  protected:
+    void SetLastChannel(uint channel);
+    void ProcessPATPacket(const TSPacket&);
+
+    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;
+};
+
+inline bool FirewireDevice::IsSTBSupported(const QString &panel_model)
+{
+#ifdef USING_LINUX_FIREWIRE
+    QString model = panel_model.upper();
+    return ((model == "DCT-6200") ||
+            (model == "SA3250HD") ||
+	    (model == "SA4200HD"));
+#elif USING_OSX_FIREWIRE
+    return true;
+#else
+    return false;
+#endif
+}
+
+#endif // _FIREWIRE_DEVICE_H_
Index: libs/libmythtv/linuxfirewiredevice.cpp
===================================================================
--- libs/libmythtv/linuxfirewiredevice.cpp	(revision 0)
+++ libs/libmythtv/linuxfirewiredevice.cpp	(revision 0)
@@ -0,0 +1,981 @@
+/**
+ *  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 <libiec61883/iec61883.h>
+#include <libavc1394/avc1394.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)
+
+
+#ifndef AVC1394_PANEL_COMMAND_PASS_THROUGH
+#define AVC1394_PANEL_COMMAND_PASS_THROUGH     0x000007C00
+#endif
+
+#ifndef AVC1394_PANEL_OPERATION_0
+#define AVC1394_PANEL_OPERATION_0              0x000000020
+#endif
+
+#define AVC1394_CMD_OPERAND_POWER_STATE        0x7F
+
+// Basic Panel commands
+#define PANEL_CMD0 (AVC1394_CTYPE_CONTROL | \
+                    AVC1394_SUBUNIT_TYPE_PANEL | \
+                    AVC1394_SUBUNIT_ID_0 | \
+                    AVC1394_PANEL_COMMAND_PASS_THROUGH)
+
+// Scientific Atlanta defines
+#define AVC1394_SA3250_OPERAND_KEY_PRESS	0xE7
+#define AVC1394_SA3250_OPERAND_KEY_RELEASE	0x67
+#define SA_CMD0     PANEL_CMD0
+#define SA_CMD1     AVC1394_CTYPE_GENERAL_INQUIRY
+#define SA_CMD2     0xff000000
+
+// Motorola defines
+#define MOT_CMD0  (PANEL_CMD0 | AVC1394_PANEL_OPERATION_0)
+
+class LFDPriv
+{
+  public:
+    LFDPriv() :
+        handle(0), avstream(0),
+        channel(-1),
+        is_p2p_node_open(false), is_bcast_node_open(false),
+        is_streaming(false)
+    {
+        bzero(unit_table, sizeof(unit_table));
+    }
+
+    raw1394handle_t  handle;
+    iec61883_mpeg2_t avstream;
+    quadlet_t        unit_table[8];
+    int              channel;
+    int              open_node;
+    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;
+};
+
+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 quadlet_t *send_avc_command(raw1394handle_t handle,
+                                   uint            node,
+                                   quadlet_t      *cmd,
+                                   uint            cmd_len,
+                                   uint            retry_cnt = 1);
+static void close_avc_command(raw1394handle_t handle);
+
+
+LinuxFirewireDevice::LinuxFirewireDevice(
+    uint port, uint node, uint speed, bool use_p2p,
+    uint av_buffer_size_in_bytes) :
+    m_port(port),       m_node(node),
+    m_speed(speed),     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;
+    }
+}
+
+bool LinuxFirewireDevice::OpenPort(void)
+{
+    QMutexLocker locker(&m_lock);
+
+    VERBOSE(VB_RECORD, LOC + "OpenPort()");
+
+    m_open_port_cnt++;
+
+    if (m_priv->handle)
+        return true;
+
+    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;
+    }
+
+    if (avc1394_subunit_info(m_priv->handle, m_node, m_priv->unit_table) < 0)
+        bzero(m_priv->unit_table, sizeof(m_priv->unit_table));
+
+    QString str = "Subunit Types: ";
+
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_MONITOR))
+        str += "Video Monitor, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_AUDIO))
+        str += "Audio, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PRINTER))
+        str += "Printer, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_DISC_RECORDER))
+        str += "Disk Recorder, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TAPE_RECORDER))
+        str += "Tape Recorder, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VCR))
+        str += "VCR, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER))
+        str += "Tuner, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CA))
+        str += "CA, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VIDEO_CAMERA))
+        str += "Camera, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL))
+        str += "Panel, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_BULLETIN_BOARD))
+        str += "Bulletin Board, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_CAMERA_STORAGE))
+        str += "Camera Storage, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_MUSIC))
+        str += "Music, ";
+    if (IsSubunitType(AVC1394_SUBUNIT_TYPE_VENDOR_UNIQUE))
+        str += "Vendor Unique, ";
+
+    VERBOSE(VB_RECORD, LOC + str);
+
+    return true;
+}
+
+bool LinuxFirewireDevice::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 (m_priv->handle)
+    {
+        if (IsNodeOpen())
+            CloseNode();
+
+        VERBOSE(VB_RECORD, LOC + "Releasing raw1394 handle "<<m_open_port_cnt);
+        raw1394_destroy_handle(m_priv->handle);
+        m_priv->handle = NULL;
+    }
+
+    return true;
+}
+
+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(50)) ? 0 : no_data_cnt + 1;
+
+        if (m_priv->is_streaming && (no_data_cnt > 30))
+        {
+            no_data_cnt = 0;
+
+            iec61883_mpeg2_recv_stop(m_priv->avstream);
+            raw1394_iso_recv_flush(m_priv->handle);
+            m_priv->is_streaming = false;
+            ResetBus();
+            iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel);
+            m_priv->is_streaming = true;
+        }
+    }
+
+    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->avstream)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no A/V obj");
+        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(50);
+        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(50);
+            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::IsSubunitType(uint subunit_type) const
+{
+    for (uint i = 0; i < 8; i++)
+    {
+        for (uint j = 0; j < 32; j += 8)
+        {
+            uint subunit = (m_priv->unit_table[i] >> j) & 0xff;
+            if ((subunit != 0xff) &&
+                (subunit >> 3) == AVC1394_GET_SUBUNIT_TYPE(subunit_type))
+            {
+                return true;
+            }
+        }
+    }
+    return false; 
+}
+
+bool LinuxFirewireDevice::IsTuner(void) const
+{
+    QMutexLocker locker(&m_lock);
+
+    return IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER);
+}
+
+bool LinuxFirewireDevice::IsPanel(void) const
+{
+    QMutexLocker locker(&m_lock);
+
+    return IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL);
+}
+
+bool LinuxFirewireDevice::IsSTB(void) const
+{
+    QMutexLocker locker(&m_lock);
+
+    return (IsSubunitType(AVC1394_SUBUNIT_TYPE_TUNER) &&
+            IsSubunitType(AVC1394_SUBUNIT_TYPE_PANEL));
+}
+
+bool LinuxFirewireDevice::IsPortOpen(void) const
+{
+    QMutexLocker locker(&m_lock);
+
+    return m_priv->handle;
+}
+
+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)
+{
+    if (m_priv->is_streaming)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "ResetBus() can not be called while streaming");
+    }
+
+    m_resetting = true;
+    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- begin");
+
+    bool open_node     = IsNodeOpen();
+    bool open_avstream = IsAVStreamOpen();
+
+    CloseAVStream();
+    CloseNode();
+
+    bool ok = (raw1394_reset_bus_new(m_priv->handle, RAW1394_LONG_RESET) == 0);
+    if (!ok)
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed" + ENO);
+
+    if (open_node)
+        ok &= OpenNode();
+
+    if (open_avstream)
+        ok &= OpenAVStream();
+
+    VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end");
+    m_resetting = false;
+
+    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::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();
+    }
+}
+
+void LinuxFirewireDevice::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);
+}
+
+bool LinuxFirewireDevice::SetChannel(const QString &panel_model, 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 (panel_model.upper() == "DCT-6200")
+    {
+        for (uint i = 0; i < 3 ;i++)
+        {
+            quadlet_t cmd[2] =
+            {
+                MOT_CMD0 | AVC1394_PANEL_OPERATION_0 | digit[i],
+                0x0,
+            };
+
+            if (!send_avc_command(m_priv->handle, m_node, cmd, 2))
+                return false;
+
+            usleep(500000);
+        }
+
+        SetLastChannel(channel);
+        return true;
+    }
+
+    if (panel_model.upper() == "SA4200HD")
+    {
+        quadlet_t cmd[3] =
+        {
+            SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS,
+            SA_CMD1 | (channel << 8),
+            SA_CMD2,
+        };
+
+        if (!send_avc_command(m_priv->handle, m_node, cmd, 3))
+            return false;
+
+        SetLastChannel(channel);
+        return true;
+    }
+   
+    if (panel_model == "SA3250HD")
+    {
+        digit[0] |= 0x30;
+        digit[1] |= 0x30;
+        digit[2] |= 0x30;
+
+        quadlet_t cmd[3] =
+        {
+            SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_PRESS, 
+            SA_CMD1 | (digit[2] << 16) | (digit[1] << 8) | digit[0],
+            SA_CMD2,
+        };
+
+        VERBOSE(VB_CHANNEL, LOC +
+                QString("Channel2: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
+                .arg(digit[0] & 0xf).arg(digit[1] & 0xf)
+                .arg(digit[2] & 0xf)
+                .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
+                .arg(cmd[2], 0, 16));
+
+        if (!send_avc_command(m_priv->handle, m_node, cmd, 3))
+            return false;
+
+        cmd[0] = SA_CMD0 | AVC1394_SA3250_OPERAND_KEY_RELEASE;
+        cmd[1] = SA_CMD1 | (digit[0] << 16) | (digit[1] << 8) | digit[2];
+        cmd[2] = SA_CMD2;
+
+        VERBOSE(VB_CHANNEL, LOC +
+                QString("Channel3: %1%2%3 cmds: 0x%4, 0x%5, 0x%6")
+                .arg(digit[0] & 0xf).arg(digit[1] & 0xf)
+                .arg(digit[2] & 0xf)
+                .arg(cmd[0], 0, 16).arg(cmd[1], 0, 16)
+                .arg(cmd[2], 0, 16));
+
+        if (!send_avc_command(m_priv->handle, m_node, cmd, 3))
+            return false;
+
+        SetLastChannel(channel);
+        return true;
+    }
+
+    return false;
+}
+
+bool LinuxFirewireDevice::SetPowerState(bool on)
+{
+    QMutexLocker locker(&m_lock);
+
+    quadlet_t cmd =
+        AVC1394_CTYPE_CONTROL     | AVC1394_SUBUNIT_TYPE_UNIT |
+        AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER;
+
+    cmd |= (on) ? AVC1394_CMD_OPERAND_POWER_ON : AVC1394_CMD_OPERAND_POWER_OFF;
+
+    QString cmdStr = (on) ? "on" : "off";
+    VERBOSE(VB_RECORD, LOC + QString("Powering %1 (cmd: 0x%2)")
+            .arg(cmdStr).arg(cmd, 0, 16));
+
+    quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1);
+
+    if (!rval)
+    {
+        close_avc_command(m_priv->handle);
+        VERBOSE(VB_IMPORTANT, LOC + "Power on cmd failed (no response)");
+        return false;
+    }
+
+    quadlet_t response = rval[0];
+    close_avc_command(m_priv->handle);
+
+    if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_ACCEPTED)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("Power %1 cmd failed (0x%2)")
+                .arg(cmdStr).arg(response, 0, 16));
+
+        return false;
+    }
+
+    VERBOSE(VB_RECORD, LOC +
+            QString("Power %1 cmd sent successfully (0x%2)")
+            .arg(cmdStr).arg(response, 0, 16));
+
+    return true;
+}
+
+FirewireDevice::PowerState LinuxFirewireDevice::GetPowerState(void)
+{
+    QMutexLocker locker(&m_lock);
+
+    quadlet_t cmd =
+        AVC1394_CTYPE_STATUS      | AVC1394_SUBUNIT_TYPE_UNIT |
+        AVC1394_SUBUNIT_ID_IGNORE | AVC1394_COMMAND_POWER     |
+        AVC1394_CMD_OPERAND_POWER_STATE;
+
+    VERBOSE(VB_CHANNEL, LOC + QString("Requesting STB Power State (cmd: 0x%1)")
+            .arg(cmd, 0, 16));
+
+    quadlet_t *rval = send_avc_command(m_priv->handle, m_node, &cmd, 1);
+
+    if (!rval)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get STB Power State");
+        return kAVCPowerQueryFailed;
+    }
+
+    quadlet_t response = rval[0];
+    // TODO we probably need to call close_avc_command(m_priv->handle)...
+
+    QString loc = LOC + "STB Power State: ";
+    QString rs  = QString(" (0x%1)").arg(response, 0, 16);
+
+    if (AVC1394_MASK_RESPONSE(response) != AVC1394_RESPONSE_IMPLEMENTED)
+    {
+        VERBOSE(VB_CHANNEL, loc + "Query not implemented" + rs);
+        return kAVCPowerUnknown;
+    }
+
+    if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_ON)
+    {
+        VERBOSE(VB_CHANNEL, loc + "On" + rs);
+        return kAVCPowerOn;
+    }
+
+    if (AVC1394_MASK_OPERAND0(response) == AVC1394_CMD_OPERAND_POWER_OFF)
+    {
+        VERBOSE(VB_CHANNEL, loc + "Off" + rs);
+        return kAVCPowerOff;
+    }
+    
+    VERBOSE(VB_IMPORTANT, LOC_ERR + "STB Power State: Unknown Response" + rs);
+
+    return kAVCPowerUnknown;
+}
+
+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));
+    }
+}
+
+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 > RAW1394_ISO_SPEED_400)
+        return QString("Invalid Speed (%1)").arg(speed);
+
+    static const uint speeds[] = { 100, 200, 400, };
+    return QString("%1Mbps").arg(speeds[speed]);
+}
+
+static quadlet_t *send_avc_command(raw1394handle_t handle,
+                                   uint            node,
+                                   quadlet_t      *cmd,
+                                   uint            cmd_len,
+                                   uint            retry_cnt)
+{
+    if (!handle)
+        return NULL;
+
+    quadlet_t *ret = avc1394_transaction_block(
+        handle, node, cmd, cmd_len, retry_cnt);
+
+    if (!ret)
+        VERBOSE(VB_IMPORTANT, "AVC transaction failed.");
+
+    return ret;
+}
+
+static void close_avc_command(raw1394handle_t handle)
+{
+    if (handle)
+        avc1394_transaction_block_close(handle);
+}
+
