Ticket #4752: r5000_r7.patch

File r5000_r7.patch, 124.0 KB (added by alannisota@…, 16 years ago)

Rev 7 of myth patch

  • configure

    old new  
    158158  echo "  --disable-v4l            disable Video4Linux support"
    159159  echo "  --disable-ivtv           disable ivtv support (PVR-x50) req. v4l support"
    160160  echo "  --disable-dvb            disable DVB support"
     161  echo "  --disable-r5000          disable support for R5000 USB STBs"
    161162  echo "  --dvb-path=HDRLOC        location of directory containing"
    162163  echo "                           'linux/dvb/frontend.h', not the"
    163164  echo "                           directory with frontend.h [$dvb_path]"
     
    888889    hdhomerun
    889890    iptv
    890891    ivtv
     892    r5000
    891893    joystick_menu
    892894    libfftw3
    893895    lirc
     
    10421044dbox2_deps="backend"
    10431045dvb_deps="backend"
    10441046firewire_deps="backend"
     1047r5000_deps="backend"
    10451048iptv_deps="backend"
    10461049ivtv_deps="backend v4l"
    10471050hdhomerun_deps="backend"
     
    11751178hdhomerun="yes"
    11761179iptv="yes"
    11771180ivtv="yes"
     1181r5000="yes"
    11781182joystick_menu="default"
    11791183lamemp3="yes"
    11801184lirc="yes"
     
    29722976  echo "DBox2 support             ${dbox2-no}"
    29732977  echo "HDHomeRun support         ${hdhomerun-no}"
    29742978  echo "IPTV support              ${iptv-no}"
     2979  echo "R5000 support             ${r5000-no}"
    29752980fi
    29762981
    29772982if enabled frontend; then
  • libs/libmythtv/cardutil.h

    old new  
    5353        FIREWIRE,
    5454        HDHOMERUN,
    5555        FREEBOX,
     56        R5000,
    5657    };
    5758
    5859    static enum CARD_TYPES toCardType(const QString &name)
     
    8182            return HDHOMERUN;
    8283        if ("FREEBOX" == name)
    8384            return FREEBOX;
     85        if ("R5000" == name)
     86            return R5000;
    8487        return ERROR_UNKNOWN;
    8588    }
    8689
     
    8992        return
    9093            (rawtype != "DVB")       &&
    9194            (rawtype != "FIREWIRE")  && (rawtype != "DBOX2")   &&
    92             (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX");
     95            (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX") &&
     96            (rawtype != "R5000");
    9397    }
    9498
    9599    static bool         IsUnscanable(const QString &rawtype)
    96100    {
    97101        return
    98             (rawtype == "FIREWIRE")  || (rawtype == "DBOX2");
     102            (rawtype == "FIREWIRE")  || (rawtype == "DBOX2") ||
     103            (rawtype == "R5000");
    99104    }
    100105
    101106    static bool         IsEITCapable(const QString &rawtype)
  • libs/libmythtv/libmythtv.pro

    old new  
    491491        DEFINES += USING_DVB
    492492    }
    493493
     494    #Support for R5000 usb device
     495    using_r5000 {
     496        HEADERS += r5000channel.h           r5000recorder.h
     497        HEADERS += r5000signalmonitor.h     r5000device.h
     498        HEADERS += r5000/r5000.h            r5000/libusb_augment.h
     499        HEADERS += r5000/r5000_internal.h   r5000/r5000init.h
     500
     501        SOURCES += r5000channel.cpp         r5000recorder.cpp
     502        SOURCES += r5000signalmonitor.cpp   r5000device.cpp
     503        SOURCES += r5000/r5000.c            r5000/libusb_augment.c
     504        SOURCES += r5000/r5k_vip.c          r5000/r5k_directv.c
     505        SOURCES += r5000/r5k_sat.c          r5000/r5k_misc.c
     506
     507        LIBS += -lusb
     508        DEFINES += USING_R5000
     509    }
     510
    494511    DEFINES += USING_BACKEND
    495512}
    496513
  • libs/libmythtv/signalmonitor.h

    old new  
    297297            (cardtype.upper() == "HDTV")      ||
    298298            (cardtype.upper() == "HDHOMERUN") ||
    299299            (cardtype.upper() == "FIREWIRE")  ||
    300             (cardtype.upper() == "FREEBOX"));
     300            (cardtype.upper() == "FREEBOX")   ||
     301            (cardtype.upper() == "R5000"));
    301302}
    302303
    303304inline bool SignalMonitor::IsSupported(const QString &cardtype)
  • libs/libmythtv/signalmonitor.cpp

    old new  
    4141#   include "firewirechannel.h"
    4242#endif
    4343
     44#ifdef USING_R5000
     45#   include "r5000signalmonitor.h"
     46#   include "r5000channel.h"
     47#endif
     48
    4449#undef DBG_SM
    4550#define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \
    4651    "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG);
     
    127132            signalMonitor = new FirewireSignalMonitor(db_cardnum, fc);
    128133    }
    129134#endif
     135#ifdef USING_R5000
     136    if (cardtype.upper() == "R5000")
     137    {
     138        R5000Channel *fc = dynamic_cast<R5000Channel*>(channel);
     139        if (fc)
     140            signalMonitor = new R5000SignalMonitor(db_cardnum, fc);
     141    }
     142#endif
    130143
    131144    if (!signalMonitor)
    132145    {
  • libs/libmythtv/cardutil.cpp

    old new  
    14571457    if (("FIREWIRE"  == cardtype) ||
    14581458        ("FREEBOX"   == cardtype) ||
    14591459        ("DBOX2"     == cardtype) ||
    1460         ("HDHOMERUN" == cardtype))
     1460        ("HDHOMERUN" == cardtype) ||
     1461        ("R5000"     == cardtype))
    14611462    {
    14621463        ret += "MPEG2TS";
    14631464    }
     
    15821583    if (("FIREWIRE"  == cardtype) ||
    15831584        ("FREEBOX"   == cardtype) ||
    15841585        ("DBOX2"     == cardtype) ||
    1585         ("HDHOMERUN" == cardtype))
     1586        ("HDHOMERUN" == cardtype) ||
     1587        ("R5000"     == cardtype))
    15861588    {
    15871589        inputs += "MPEG2TS";
    15881590    }
  • libs/libmythtv/videosource.cpp

    old new  
    3636#include "frequencies.h"
    3737#include "diseqcsettings.h"
    3838#include "firewiredevice.h"
     39#include "r5000device.h"
    3940#include "compat.h"
    4041
    4142
     
    12971298    }
    12981299};
    12991300
     1301class R5000Serial : public ComboBoxSetting, public CaptureCardDBStorage
     1302{
     1303  public:
     1304    R5000Serial(const CaptureCard &parent) :
     1305        ComboBoxSetting(this),
     1306        CaptureCardDBStorage(this, parent, "videodevice")
     1307    {
     1308        setLabel(QObject::tr("Serial #"));
     1309#ifdef USING_R5000
     1310        QStringList serials = R5000Device::GetSTBList();
     1311        for (uint i = 0; i < serials.size(); i++)
     1312        {
     1313            addSelection(serials[i]);
     1314        }
     1315#endif // USING_FIREWIRE
     1316    }
     1317};
     1318
     1319class R5000Model : public ComboBoxSetting, public CaptureCardDBStorage
     1320{
     1321  public:
     1322    R5000Model(const CaptureCard  &parent) :
     1323      ComboBoxSetting(this),
     1324      CaptureCardDBStorage(this, parent, "firewire_model")
     1325    {
     1326        setLabel(QObject::tr("R5000 STB type"));
     1327        addSelection("VIP211/VIP622/DISH411");
     1328        addSelection("DIRECTV");
     1329        addSelection("STARCHOICE/DSR");
     1330        addSelection("HDD-200");
     1331        QString help = QObject::tr(
     1332            "Choose the type of R5000 enabled STB you are using.");
     1333        setHelpText(help);
     1334    }
     1335};
     1336class R5000ConfigurationGroup : public VerticalConfigurationGroup
     1337{
     1338  public:
     1339    R5000ConfigurationGroup(CaptureCard& a_parent):
     1340       VerticalConfigurationGroup(false, true, false, false),
     1341       parent(a_parent)
     1342    {
     1343        setUseLabel(false);
     1344        addChild(new R5000Serial(parent));
     1345        addChild(new R5000Model(parent));
     1346        addChild(new SingleCardInput(parent));
     1347    };
     1348
     1349  private:
     1350    CaptureCard &parent;
     1351};
     1352
    13001353class IPTVHost : public LineEditSetting, public CaptureCardDBStorage
    13011354{
    13021355  public:
     
    14811534#ifdef USING_IPTV
    14821535    addTarget("FREEBOX",   new IPTVConfigurationGroup(parent));
    14831536#endif // USING_IPTV
     1537
     1538#ifdef USING_R5000
     1539    addTarget("R5000", new R5000ConfigurationGroup(parent));
     1540#endif // USING_R5000
    14841541}
    14851542
    14861543void CaptureCardGroup::triggerChanged(const QString& value)
     
    16681725#ifdef USING_IPTV
    16691726    setting->addSelection(QObject::tr("Network Recorder"), "FREEBOX");
    16701727#endif // USING_IPTV
     1728
     1729#ifdef USING_R5000
     1730    setting->addSelection(QObject::tr("R5000 Capable STB"), "R5000");
     1731#endif // USING_R5000
    16711732}
    16721733
    16731734class CardID : public SelectLabelSetting, public CardInputDBStorage
  • libs/libmythtv/tv_rec.cpp

    old new  
    5050#include "hdhrchannel.h"
    5151#include "iptvchannel.h"
    5252#include "firewirechannel.h"
     53#include "r5000channel.h"
    5354
    5455#include "recorderbase.h"
    5556#include "NuppelVideoRecorder.h"
     
    5960#include "hdhrrecorder.h"
    6061#include "iptvrecorder.h"
    6162#include "firewirerecorder.h"
     63#include "r5000recorder.h"
    6264
    6365#ifdef USING_V4L
    6466#include "channel.h"
     
    199201        init_run = true;
    200202#endif
    201203    }   
     204    else if (genOpt.cardtype == "R5000")
     205    {
     206#ifdef USING_R5000
     207        channel = new R5000Channel(this, genOpt.videodev, fwOpt.model);
     208        if (!channel->Open())
     209            return false;
     210        InitChannel(genOpt.defaultinput, startchannel);
     211        init_run = true;
     212#endif
     213    }
    202214    else // "V4L" or "MPEG", ie, analog TV
    203215    {
    204216#ifdef USING_V4L
     
    10171029        recorder->SetOption("mrl", genOpt.videodev);
    10181030#endif // USING_IPTV
    10191031    }
     1032    else if (genOpt.cardtype == "R5000")
     1033    {
     1034#ifdef USING_R5000
     1035        recorder = new R5000Recorder(this, GetR5000Channel());
     1036#endif // USING_R5000
     1037    }
    10201038    else
    10211039    {
    10221040#ifdef USING_V4L
     
    12301248#endif // USING_FIREWIRE
    12311249}
    12321250
     1251R5000Channel *TVRec::GetR5000Channel(void)
     1252{
     1253#ifdef USING_R5000
     1254    return dynamic_cast<R5000Channel*>(channel);
     1255#else
     1256    return NULL;
     1257#endif // USING_R5000
     1258}
     1259
    12331260Channel *TVRec::GetV4LChannel(void)
    12341261{
    12351262#ifdef USING_V4L
  • libs/libmythtv/transporteditor.cpp

    old new  
    735735        left->addChild(new Modulation(id, nType));
    736736    }
    737737    else if ((CardUtil::FIREWIRE == nType) ||
    738              (CardUtil::FREEBOX  == nType))
     738             (CardUtil::FREEBOX  == nType) ||
     739             (CardUtil::R5000    == nType))
    739740    {
    740741        left->addChild(new DTVStandard(id, true, true));
    741742    }
  • libs/libmythtv/tv_rec.h

    old new  
    3939class FirewireChannel;
    4040class Channel;
    4141class HDHRChannel;
     42class R5000Channel;
    4243
    4344class MPEGStreamData;
    4445class ProgramMapTable;
     
    281282    HDHRChannel  *GetHDHRChannel(void);
    282283    DVBChannel   *GetDVBChannel(void);
    283284    FirewireChannel *GetFirewireChannel(void);
     285    R5000Channel *GetR5000Channel(void);
    284286    Channel      *GetV4LChannel(void);
    285287
    286288    bool SetupSignalMonitor(bool enable_table_monitoring, bool notify);
  • new file libs/libmythtv/r5000channel.cpp

    - +  
     1/**
     2 *  R5000Channel
     3 *  Copyright (c) 2005 by Jim Westfall, Dave Abrahams
     4 *  Copyright (c) 2006 by Daniel Kristjansson
     5 *  Distributed as part of MythTV under GPL v2 and later.
     6 */
     7
     8#include "mythcontext.h"
     9#include "tv_rec.h"
     10#include "r5000channel.h"
     11
     12#define LOC QString("R5kChan(%1): ").arg(GetDevice())
     13#define LOC_WARN QString("R5kChan(%1), Warning: ").arg(GetDevice())
     14#define LOC_ERR QString("R5kChan(%1), Error: ").arg(GetDevice())
     15
     16R5000Channel::R5000Channel(TVRec *parent, const QString &_videodevice,const QString &_r5ktype) :
     17    DTVChannel(parent),
     18    videodevice(_videodevice),
     19    device(NULL),
     20    current_channel(0),
     21    isopen(false)
     22{
     23    int type = R5000Device::GetDeviceType(_r5ktype);
     24    device = new R5000Device(type, videodevice);
     25
     26    InitializeInputs();
     27}
     28
     29bool R5000Channel::SetChannelByString(const QString &channum)
     30{
     31    QString loc = LOC + QString("SetChannelByString(%1)").arg(channum);
     32    bool ok = true;
     33    VERBOSE(VB_CHANNEL, loc);
     34
     35    InputMap::const_iterator it = inputs.find(currentInputID);
     36    if (it == inputs.end())
     37        return false;
     38
     39    QString tvformat, modulation, freqtable, freqid, dtv_si_std;
     40    int finetune;
     41    uint64_t frequency;
     42    int mpeg_prog_num;
     43    uint atsc_major, atsc_minor, mplexid, tsid, netid;
     44    if (!ChannelUtil::GetChannelData(
     45        (*it)->sourceid, channum,
     46        tvformat, modulation, freqtable, freqid,
     47        finetune, frequency,
     48        dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
     49        mplexid, commfree))
     50    {
     51        VERBOSE(VB_IMPORTANT, loc + " " + QString(
     52                    "Requested channel '%1' is on input '%2' "
     53                    "which is in a busy input group")
     54                .arg(channum).arg(currentInputID));
     55
     56        return false;
     57    }
     58    uint mplexid_restriction;
     59    if (!IsInputAvailable(currentInputID, mplexid_restriction))
     60    {
     61        VERBOSE(VB_IMPORTANT, loc + " " + QString(
     62                    "Requested channel '%1' is on input '%2' "
     63                    "which is in a busy input group")
     64                .arg(channum).arg(currentInputID));
     65
     66        return false;
     67    }
     68
     69    uint ichan = freqid.toUInt(&ok);
     70    ok = isopen && SetChannelByNumber(ichan);
     71
     72    if (ok)
     73    {
     74        // Set the current channum to the new channel's channum
     75        curchannelname = QDeepCopy<QString>(channum);
     76        (*it)->startChanNum = QDeepCopy<QString>(channum);
     77    }
     78
     79    VERBOSE(VB_CHANNEL, loc + " " + ((ok) ? "success" : "failure"));
     80
     81    return ok;
     82}
     83
     84bool R5000Channel::Open(void)
     85{
     86    VERBOSE(VB_CHANNEL, LOC + "Open()");
     87
     88    if (inputs.find(currentInputID) == inputs.end())
     89        return false;
     90
     91    if (!device)
     92        return false;
     93
     94    if (isopen)
     95        return true;
     96
     97    if (!device->OpenPort())
     98        return false;
     99
     100    isopen = true;
     101
     102    return true;
     103}
     104
     105void R5000Channel::Close(void)
     106{
     107    VERBOSE(VB_CHANNEL, LOC + "Close()");
     108    if (isopen)
     109    {
     110        device->ClosePort();
     111        isopen = false;
     112    }
     113}
     114
     115QString R5000Channel::GetDevice(void) const
     116{
     117    return videodevice;
     118}
     119
     120bool R5000Channel::SetPowerState(bool on)
     121{
     122    if (!isopen)
     123    {
     124        VERBOSE(VB_IMPORTANT, LOC_ERR +
     125                "SetPowerState() called on closed R5000Channel.");
     126
     127        return false;
     128    }
     129
     130    return device->SetPowerState(on);
     131}
     132
     133R5000Device::PowerState R5000Channel::GetPowerState(void) const
     134{
     135    if (!isopen)
     136    {
     137        VERBOSE(VB_IMPORTANT, LOC_ERR +
     138                "GetPowerState() called on closed R5000Channel.");
     139
     140        return R5000Device::kAVCPowerQueryFailed;
     141    }
     142
     143    return device->GetPowerState();
     144}
     145
     146bool R5000Channel::Retune(void)
     147{
     148    VERBOSE(VB_CHANNEL, LOC + "Retune()");
     149
     150    if (R5000Device::kAVCPowerOff == GetPowerState())
     151    {
     152        VERBOSE(VB_IMPORTANT, LOC_ERR +
     153                "STB is turned off, must be on to retune.");
     154
     155        return false;
     156    }
     157
     158    if (current_channel)
     159        return SetChannelByNumber(current_channel);
     160
     161    return false;
     162}
     163
     164bool R5000Channel::SetChannelByNumber(int channel)
     165{
     166    VERBOSE(VB_CHANNEL, QString("SetChannelByNumber(%1)").arg(channel));
     167    current_channel = channel;
     168
     169    if (R5000Device::kAVCPowerOff == GetPowerState())
     170    {
     171        VERBOSE(VB_IMPORTANT, LOC_WARN +
     172                "STB is turned off, must be on to set channel.");
     173
     174        SetSIStandard("mpeg");
     175        SetDTVInfo(0,0,0,0,1);
     176
     177        return true; // signal monitor will call retune later...
     178    }
     179
     180    if (!device->SetChannel(fw_opts.model, 0, channel))
     181        return false;
     182
     183    SetSIStandard("mpeg");
     184    SetDTVInfo(0,0,0,0,1);
     185
     186    return true;
     187}
  • new file libs/libmythtv/r5000device.cpp

    - +  
     1/**
     2 *  R5000Device
     3 *  Copyright (c) 2008 by Alan Nisota
     4 *  Copyright (c) 2005 by Jim Westfall
     5 *  Distributed as part of MythTV under GPL v2 and later.
     6 */
     7
     8// Qt headers
     9#include <qdeepcopy.h>
     10
     11// MythTV headers
     12#include "r5000device.h"
     13#include "mythcontext.h"
     14#include "pespacket.h"
     15
     16#define LOC      QString("R5kDev: ")
     17#define LOC_WARN QString("R5kDev, Warning: ")
     18#define LOC_ERR  QString("R5kDev, Error: ")
     19
     20QMap<uint64_t,QString> R5000Device::s_id_to_model;
     21QMutex                 R5000Device::s_static_lock;
     22
     23unsigned int r5000_device_tspacket_handler(unsigned char *tspacket, int len, void *callback_data)
     24{
     25    R5000Device *fw = (R5000Device*) callback_data;
     26    if (! fw)
     27        return 0;
     28    if (len > 0)
     29        fw->BroadcastToListeners(tspacket, len);
     30    return 1;
     31}
     32
     33
     34class R5kPriv
     35{
     36  public:
     37    R5kPriv() :
     38        reset_timer_on(false),
     39        run_port_handler(false), is_port_handler_running(false),
     40        channel(-1),
     41        is_streaming(false)
     42    {
     43    }
     44
     45    bool             reset_timer_on;
     46    MythTimer        reset_timer;
     47
     48    bool             run_port_handler;
     49    bool             is_port_handler_running;
     50    QMutex           start_stop_port_handler_lock;
     51
     52    int              channel;
     53
     54    bool             is_streaming;
     55
     56    QDateTime        stop_streaming_timer;
     57    pthread_t        port_handler_thread;
     58
     59    static QMutex           s_lock;
     60};
     61QMutex          R5kPriv::s_lock;
     62
     63//callback functions
     64void *r5000_device_port_handler_thunk(void *param);
     65
     66R5000Device::R5000Device(int type, QString serial) :
     67    m_type(type),
     68    m_serial(serial),
     69    m_last_channel(0),      m_last_crc(0),
     70    m_buffer_cleared(true), m_open_port_cnt(0),
     71    m_lock(false),          m_priv(new R5kPriv())
     72{
     73  usbdev = NULL;
     74}
     75
     76R5000Device::~R5000Device()
     77{
     78    if (usbdev)
     79    {
     80        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
     81        while(usbdev)
     82            ClosePort();
     83    }
     84
     85    if (m_priv)
     86    {
     87        delete m_priv;
     88        m_priv = NULL;
     89    }
     90}
     91
     92void R5000Device::AddListener(TSDataListener *listener)
     93{
     94    if (listener)
     95    {
     96        vector<TSDataListener*>::iterator it =
     97            find(m_listeners.begin(), m_listeners.end(), listener);
     98
     99        if (it == m_listeners.end())
     100            m_listeners.push_back(listener);
     101    }
     102
     103    VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size());
     104    if (!m_listeners.empty())
     105    {
     106        StartStreaming();
     107    }
     108}
     109
     110void R5000Device::RemoveListener(TSDataListener *listener)
     111{
     112    vector<TSDataListener*>::iterator it = m_listeners.end();
     113
     114    do
     115    {
     116        it = find(m_listeners.begin(), m_listeners.end(), listener);
     117        if (it != m_listeners.end())
     118            m_listeners.erase(it);
     119    }
     120    while (it != m_listeners.end());
     121
     122    VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size());
     123    if (m_listeners.empty())
     124    {
     125        StopStreaming();
     126    }
     127}
     128
     129bool R5000Device::StartStreaming(void)
     130{
     131    if (m_priv->is_streaming)
     132        return m_priv->is_streaming;
     133
     134    if (! usbdev)
     135    {
     136        VERBOSE(VB_IMPORTANT, LOC_ERR + "Device not open");
     137        return false;
     138    }
     139    if (r5000_start_stream(usbdev))
     140    {
     141        m_priv->is_streaming = true;
     142    }
     143    else
     144    {
     145        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming ");
     146    }
     147
     148    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- done");
     149
     150    return m_priv->is_streaming;
     151}
     152
     153bool R5000Device::StopStreaming(void)
     154{
     155    if (m_priv->is_streaming)
     156    {
     157        VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really");
     158
     159        m_priv->is_streaming = false;
     160
     161        r5000_stop_stream(usbdev);
     162    }
     163
     164    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
     165
     166    return true;
     167}
     168
     169bool R5000Device::SetPowerState(bool on)
     170{
     171    QMutexLocker locker(&m_lock);
     172    QString cmdStr = (on) ? "on" : "off";
     173    VERBOSE(VB_RECORD, LOC + QString("Powering %1").arg(cmdStr));
     174    if(r5000_get_power_state(usbdev) != on)
     175      r5000_toggle_on_off(usbdev);
     176    return true;
     177}
     178
     179R5000Device::PowerState R5000Device::GetPowerState(void)
     180{
     181    QMutexLocker locker(&m_lock);
     182    int on_off;
     183
     184    VERBOSE(VB_CHANNEL, LOC + "Requesting STB Power State");
     185    on_off = r5000_get_power_state(usbdev);
     186    VERBOSE(VB_CHANNEL, LOC + (on_off ? "On" : "Off"));
     187    return on_off ? kAVCPowerOn : kAVCPowerOff;
     188}
     189
     190bool R5000Device::SetChannel(const QString &panel_model,
     191                                uint alt_method, uint channel)
     192{
     193    VERBOSE(VB_CHANNEL, QString("SetChannel(model %1, alt %2, chan %3)")
     194            .arg(panel_model).arg(alt_method).arg(channel));
     195
     196    QMutexLocker locker(&m_lock);
     197    VERBOSE(VB_CHANNEL, "SetChannel() -- locked");
     198    if(! r5000_change_channel(usbdev, channel))
     199        VERBOSE(VB_IMPORTANT, LOC + "Failed to set channel");
     200    return true;
     201}
     202
     203void R5000Device::BroadcastToListeners(
     204    const unsigned char *data, uint dataSize)
     205{
     206    if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) &&
     207        ((data[1] & 0x1f) == 0) && (data[2] == 0))
     208    {
     209        ProcessPATPacket(*((const TSPacket*)data));
     210    }
     211
     212    vector<TSDataListener*>::iterator it = m_listeners.begin();
     213    for (; it != m_listeners.end(); ++it)
     214        (*it)->AddData(data, dataSize);
     215}
     216
     217void R5000Device::SetLastChannel(const uint channel)
     218{
     219    m_buffer_cleared = (channel == m_last_channel);
     220    m_last_channel   = channel;
     221
     222    VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2")
     223            .arg(channel).arg(m_buffer_cleared ? "yes" : "no"));
     224}
     225
     226void R5000Device::ProcessPATPacket(const TSPacket &tspacket)
     227{
     228    if (!tspacket.TransportError() && !tspacket.ScramplingControl() &&
     229        tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID())
     230    {
     231        PESPacket pes = PESPacket::View(tspacket);
     232        uint crc = pes.CalcCRC();
     233        m_buffer_cleared |= (crc != m_last_crc);
     234        m_last_crc = crc;
     235#if 0
     236        VERBOSE(VB_RECORD, LOC +
     237                QString("ProcessPATPacket: CRC 0x%1 cleared: %2")
     238                .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no"));
     239#endif
     240    }
     241    else
     242    {
     243        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's");
     244    }
     245}
     246
     247QString R5000Device::GetModelName(uint vendor_id, uint model_id)
     248{
     249    QMutexLocker locker(&s_static_lock);
     250/*
     251    if (s_id_to_model.empty())
     252        fw_init(s_id_to_model);
     253
     254    QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id];
     255
     256    if (ret.isEmpty())
     257        return "GENERIC";
     258*/
     259    return "R5000";
     260}
     261
     262bool R5000Device::IsSTBSupported(const QString &panel_model)
     263{
     264    return true;
     265}
     266
     267bool R5000Device::OpenPort(void)
     268{
     269    VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread");
     270    QMutexLocker mlocker(&m_lock);
     271    VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread -- locked");
     272    if(usbdev) {
     273        m_open_port_cnt++;
     274        return true;
     275    }
     276
     277    if(m_serial) {
     278      VERBOSE(VB_RECORD, LOC + "Opening R5000 device with serial#: "+ m_serial);
     279      usbdev = r5000_open((r5ktype_t)m_type, r5000_device_tspacket_handler, this, m_serial.ascii());
     280    } else {
     281      VERBOSE(VB_RECORD, LOC + "Opening R5000 device with unknown serial#");
     282      usbdev = r5000_open((r5ktype_t)m_type, r5000_device_tspacket_handler, this, NULL);
     283    }
     284    if(! usbdev) {
     285        VERBOSE(VB_IMPORTANT, LOC + "Failed to open R5000 device");
     286        return false;
     287    }
     288
     289    VERBOSE(VB_RECORD, LOC + "Starting port handler thread");
     290    m_priv->run_port_handler = true;
     291    pthread_create(&m_priv->port_handler_thread, NULL,
     292                   r5000_device_port_handler_thunk, this);
     293
     294    VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to start");
     295    while (!m_priv->is_port_handler_running)
     296    {
     297        m_lock.unlock();
     298        usleep(5000);
     299        m_lock.lock();
     300    }
     301
     302    VERBOSE(VB_RECORD, LOC + "Port handler thread started");
     303
     304    m_open_port_cnt++;
     305
     306    return true;
     307}
     308
     309bool R5000Device::ClosePort(void)
     310{
     311    VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread");
     312    QMutexLocker locker(&m_priv->start_stop_port_handler_lock);
     313    VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread -- locked");
     314
     315    QMutexLocker mlocker(&m_lock);
     316
     317    VERBOSE(VB_RECORD, LOC + "ClosePort()");
     318
     319    if (m_open_port_cnt < 1)
     320        return false;
     321
     322    m_open_port_cnt--;
     323
     324    if (m_open_port_cnt != 0)
     325        return true;
     326
     327    if (!usbdev)
     328        return false;
     329
     330    VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to stop");
     331    m_priv->run_port_handler = false;
     332    while (m_priv->is_port_handler_running)
     333    {
     334        m_lock.unlock();
     335        usleep(5000);
     336        m_lock.lock();
     337    }
     338    VERBOSE(VB_RECORD, LOC + "Joining port handler thread");
     339    pthread_join(m_priv->port_handler_thread, NULL);
     340
     341    r5000_close(usbdev);
     342    usbdev = NULL;
     343
     344    return true;
     345}
     346
     347void *r5000_device_port_handler_thunk(void *param)
     348{
     349    R5000Device *mon = (R5000Device*) param;
     350    mon->RunPortHandler();
     351    return NULL;
     352}
     353
     354void R5000Device::RunPortHandler(void)
     355{
     356    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start");
     357    m_lock.lock();
     358    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock");
     359    m_priv->is_port_handler_running = true;
     360    m_lock.unlock();
     361
     362    while (m_priv->run_port_handler)
     363    {
     364        if (m_priv->is_streaming) {
     365            // This will timeout after 10ms regardless of data availability
     366            r5000_loop_iterate(usbdev, 10);
     367        } else {
     368            usleep(10000);
     369        }
     370    }
     371
     372    m_lock.lock();
     373    m_priv->is_port_handler_running = false;
     374    m_lock.unlock();
     375    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end");
     376}
     377
     378QStringList R5000Device::GetSTBList(void)
     379{
     380    QStringList STBList;
     381    int i;
     382    r5kenum_t r5k_stbs;
     383    if (! r5000_find_stbs(&r5k_stbs))
     384        VERBOSE(VB_IMPORTANT, LOC + "Locating R5000 devices failed."
     385                                    "  This may be a permission problem");
     386
     387    for (i = 0; i < r5k_stbs.count; i++)
     388        STBList.append((char *)r5k_stbs.serial[i]);
     389    return STBList;
     390}
     391
     392int R5000Device::GetDeviceType(const QString &r5ktype)
     393{
     394  QString type = r5ktype.upper();
     395  if(type == "DIRECTV") {
     396    return R5K_STB_DIRECTV;
     397  } else if(type == "VIP211/VIP622/DISH411" ||
     398            type == "VIP211/VIP422") {
     399    return R5K_STB_VIP;
     400  } else if(type == "STARCHOICE/DSR") {
     401    return R5K_STB_DSR;
     402  } else if(type == "HDD-200") {
     403    return R5K_STB_HDD;
     404  } else {
     405    return R5K_STB_VIP;
     406  }
     407}
  • new file libs/libmythtv/r5000recorder.cpp

    - +  
     1/**
     2 *  R5000Recorder
     3 *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7// MythTV includes
     8#include "r5000recorder.h"
     9#include "r5000channel.h"
     10#include "mythcontext.h"
     11#include "mpegtables.h"
     12#include "mpegstreamdata.h"
     13#include "tv_rec.h"
     14
     15#define LOC QString("R5000RecBase(%1): ").arg(channel->GetDevice())
     16#define LOC_ERR QString("R5000RecBase(%1), Error: ").arg(channel->GetDevice())
     17
     18R5000Recorder::R5000Recorder(TVRec *rec, R5000Channel *chan) :
     19    DTVRecorder(rec), _mpeg_stream_data(NULL),
     20    channel(chan), isopen(false)
     21{
     22}
     23
     24R5000Recorder::~R5000Recorder()
     25{
     26    SetStreamData(NULL);
     27    Close();
     28}
     29
     30bool R5000Recorder::Open(void)
     31{
     32    if (!isopen)
     33        isopen = channel->GetR5000Device()->OpenPort();
     34
     35    return isopen;
     36}
     37
     38void R5000Recorder::Close(void)
     39{
     40    if (isopen)
     41    {
     42        channel->GetR5000Device()->ClosePort();
     43        isopen = false;
     44    }
     45}
     46
     47void R5000Recorder::StartStreaming(void)
     48{
     49    channel->GetR5000Device()->AddListener(this);
     50}
     51
     52void R5000Recorder::StopStreaming(void)
     53{
     54    channel->GetR5000Device()->RemoveListener(this);
     55}
     56
     57void R5000Recorder::StartRecording(void)
     58{
     59    VERBOSE(VB_RECORD, LOC + "StartRecording");
     60
     61    if (!Open())
     62    {
     63        _error = true;
     64        return;
     65    }
     66
     67    _request_recording = true;
     68    _recording = true;
     69
     70    StartStreaming();
     71
     72    while (_request_recording)
     73    {
     74        if (!PauseAndWait())
     75            usleep(50 * 1000);
     76    }
     77
     78    StopStreaming();
     79    FinishRecording();
     80
     81    _recording = false;
     82}
     83
     84void R5000Recorder::AddData(const unsigned char *data, uint len)
     85{
     86    uint bufsz = buffer.size();
     87    if ((SYNC_BYTE == data[0]) && (TSPacket::SIZE == len) &&
     88        (TSPacket::SIZE > bufsz))
     89    {
     90        if (bufsz)
     91            buffer.clear();
     92
     93        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data)));
     94        return;
     95    }
     96
     97    buffer.insert(buffer.end(), data, data + len);
     98    bufsz += len;
     99
     100    int sync_at = -1;
     101    for (uint i = 0; (i < bufsz) && (sync_at < 0); i++)
     102    {
     103        if (buffer[i] == SYNC_BYTE)
     104            sync_at = i;
     105    }
     106
     107    if (sync_at < 0)
     108        return;
     109
     110    if (bufsz < 30 * TSPacket::SIZE)
     111        return; // build up a little buffer
     112
     113    while (sync_at + TSPacket::SIZE < bufsz)
     114    {
     115        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(
     116                              &buffer[0] + sync_at)));
     117
     118        sync_at += TSPacket::SIZE;
     119    }
     120
     121    buffer.erase(buffer.begin(), buffer.begin() + sync_at);
     122
     123    return;
     124}
     125
     126void R5000Recorder::ProcessTSPacket(const TSPacket &tspacket)
     127{
     128    if (tspacket.TransportError())
     129        return;
     130
     131    if (tspacket.ScramplingControl())
     132        return;
     133
     134    if (tspacket.HasAdaptationField())
     135        GetStreamData()->HandleAdaptationFieldControl(&tspacket);
     136
     137    if (tspacket.HasPayload())
     138    {
     139        const unsigned int lpid = tspacket.PID();
     140        // Pass or reject packets based on PID, and parse info from them
     141        if (lpid == GetStreamData()->VideoPIDSingleProgram())
     142        {
     143            _buffer_packets = !FindMPEG2Keyframes(&tspacket);
     144            BufferedWrite(tspacket);
     145        }
     146        else if (GetStreamData()->IsAudioPID(lpid))
     147        {
     148            _buffer_packets = !FindAudioKeyframes(&tspacket);
     149            BufferedWrite(tspacket);
     150        }
     151        else if (GetStreamData()->IsListeningPID(lpid))
     152            GetStreamData()->HandleTSTables(&tspacket);
     153        else if (GetStreamData()->IsWritingPID(lpid))
     154            BufferedWrite(tspacket);
     155    }
     156}
     157
     158void R5000Recorder::SetOptionsFromProfile(RecordingProfile *profile,
     159                                                 const QString &videodev,
     160                                                 const QString &audiodev,
     161                                                 const QString &vbidev)
     162{
     163    (void)videodev;
     164    (void)audiodev;
     165    (void)vbidev;
     166    (void)profile;
     167}
     168
     169// documented in recorderbase.cpp
     170bool R5000Recorder::PauseAndWait(int timeout)
     171{
     172    if (request_pause)
     173    {
     174        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause");
     175        if (!paused)
     176        {
     177            StopStreaming();
     178            paused = true;
     179            pauseWait.wakeAll();
     180            if (tvrec)
     181                tvrec->RecorderPaused();
     182        }
     183        unpauseWait.wait(timeout);
     184    }
     185    if (!request_pause && paused)
     186    {
     187        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause");
     188        StartStreaming();
     189        paused = false;
     190    }
     191    return paused;
     192}
     193
     194void R5000Recorder::SetStreamData(MPEGStreamData *data)
     195{
     196    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- begin");
     197    if (data == _mpeg_stream_data)
     198    {
     199        VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 0");
     200        return;
     201    }
     202
     203    MPEGStreamData *old_data = _mpeg_stream_data;
     204    _mpeg_stream_data = data;
     205    if (old_data)
     206        delete old_data;
     207
     208    if (data)
     209    {
     210        data->AddMPEGSPListener(this);
     211
     212        if (data->DesiredProgram() >= 0)
     213            data->SetDesiredProgram(data->DesiredProgram());
     214    }
     215    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 1");
     216}
     217
     218void R5000Recorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
     219{
     220    if (!pat) {
     221        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPAT(NULL)");
     222        return;
     223    }
     224    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
     225    pat->tsheader()->SetContinuityCounter(next);
     226    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader())));
     227}
     228
     229void R5000Recorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
     230{
     231    if (!pmt) {
     232        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)");
     233        return;
     234    }
     235    int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
     236    pmt->tsheader()->SetContinuityCounter(next);
     237    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader())));
     238}
  • new file libs/libmythtv/r5000signalmonitor.cpp

    - +  
     1// -*- Mode: c++ -*-
     2// Copyright (c) 2006, Daniel Thor Kristjansson
     3
     4#include <pthread.h>
     5#include <fcntl.h>
     6#include <unistd.h>
     7#include <sys/select.h>
     8
     9#include "mythcontext.h"
     10#include "mythdbcon.h"
     11#include "atscstreamdata.h"
     12#include "mpegtables.h"
     13#include "atsctables.h"
     14#include "r5000channel.h"
     15#include "r5000signalmonitor.h"
     16
     17#define LOC QString("R5kSM(%1): ").arg(channel->GetDevice())
     18#define LOC_WARN QString("R5kSM(%1), Warning: ").arg(channel->GetDevice())
     19#define LOC_ERR QString("R5kSM(%1), Error: ").arg(channel->GetDevice())
     20
     21const uint R5000SignalMonitor::kPowerTimeout  = 3000; /* ms */
     22const uint R5000SignalMonitor::kBufferTimeout = 5000; /* ms */
     23
     24QMap<void*,uint> R5000SignalMonitor::pat_keys;
     25QMutex           R5000SignalMonitor::pat_keys_lock;
     26
     27/** \fn R5000SignalMonitor::R5000SignalMonitor(int,R5000Channel*,uint,const char*)
     28 *  \brief Initializes signal lock and signal values.
     29 *
     30 *   Start() must be called to actually begin continuous
     31 *   signal monitoring. The timeout is set to 3 seconds,
     32 *   and the signal threshold is initialized to 0%.
     33 *
     34 *  \param db_cardnum Recorder number to monitor,
     35 *                    if this is less than 0, SIGNAL events will not be
     36 *                    sent to the frontend even if SetNotifyFrontend(true)
     37 *                    is called.
     38 *  \param _channel R5000Channel for card
     39 *  \param _flags   Flags to start with
     40 *  \param _name    Name for Qt signal debugging
     41 */
     42R5000SignalMonitor::R5000SignalMonitor(
     43    int db_cardnum,
     44    R5000Channel *_channel,
     45    uint64_t _flags, const char *_name) :
     46    DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
     47    dtvMonitorRunning(false),
     48    stb_needs_retune(true),
     49    stb_needs_to_wait_for_pat(false),
     50    stb_needs_to_wait_for_power(false)
     51{
     52    VERBOSE(VB_CHANNEL, LOC + "ctor");
     53
     54    signalStrength.SetThreshold(65);
     55
     56    AddFlags(kDTVSigMon_WaitForSig);
     57
     58    stb_needs_retune =
     59        (R5000Device::kAVCPowerOff == _channel->GetPowerState());
     60}
     61
     62/** \fn R5000SignalMonitor::~R5000SignalMonitor()
     63 *  \brief Stops signal monitoring and table monitoring threads.
     64 */
     65R5000SignalMonitor::~R5000SignalMonitor()
     66{
     67    VERBOSE(VB_CHANNEL, LOC + "dtor");
     68    Stop();
     69}
     70
     71void R5000SignalMonitor::deleteLater(void)
     72{
     73    disconnect(); // disconnect signals we may be sending...
     74    Stop();
     75    DTVSignalMonitor::deleteLater();
     76}
     77
     78/** \fn R5000SignalMonitor::Stop(void)
     79 *  \brief Stop signal monitoring and table monitoring threads.
     80 */
     81void R5000SignalMonitor::Stop(void)
     82{
     83    VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
     84    SignalMonitor::Stop();
     85    if (dtvMonitorRunning)
     86    {
     87        dtvMonitorRunning = false;
     88        pthread_join(table_monitor_thread, NULL);
     89    }
     90    VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
     91}
     92
     93void R5000SignalMonitor::HandlePAT(const ProgramAssociationTable *pat)
     94{
     95    AddFlags(kDTVSigMon_PATSeen);
     96
     97    R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel);
     98    bool crc_bogus = !fwchan->GetR5000Device()->IsSTBBufferCleared();
     99    if (crc_bogus && stb_needs_to_wait_for_pat &&
     100        (stb_wait_for_pat_timer.elapsed() < (int)kBufferTimeout))
     101    {
     102        VERBOSE(VB_CHANNEL, LOC + "HandlePAT() ignoring PAT");
     103        uint tsid = pat->TransportStreamID();
     104        GetStreamData()->SetVersionPAT(tsid, -1,0);
     105        return;
     106    }
     107
     108    if (crc_bogus && stb_needs_to_wait_for_pat)
     109    {
     110        VERBOSE(VB_IMPORTANT, LOC_WARN + "Wait for valid PAT timed out");
     111        stb_needs_to_wait_for_pat = false;
     112    }
     113
     114    DTVSignalMonitor::HandlePAT(pat);
     115}
     116
     117void R5000SignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt)
     118{
     119    VERBOSE(VB_CHANNEL, LOC + "HandlePMT()");
     120
     121    AddFlags(kDTVSigMon_PMTSeen);
     122
     123    if (!HasFlags(kDTVSigMon_PATMatch))
     124    {
     125        GetStreamData()->SetVersionPMT(pnum, -1,0);
     126        VERBOSE(VB_CHANNEL, LOC + "HandlePMT() ignoring PMT");
     127        return;
     128    }
     129
     130    DTVSignalMonitor::HandlePMT(pnum, pmt);
     131}
     132
     133void *R5000SignalMonitor::TableMonitorThread(void *param)
     134{
     135    R5000SignalMonitor *mon = (R5000SignalMonitor*) param;
     136    mon->RunTableMonitor();
     137    return NULL;
     138}
     139
     140void R5000SignalMonitor::RunTableMonitor(void)
     141{
     142    stb_needs_to_wait_for_pat = true;
     143    stb_wait_for_pat_timer.start();
     144    dtvMonitorRunning = true;
     145
     146    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin");
     147
     148    R5000Channel *lchan = dynamic_cast<R5000Channel*>(channel);
     149    if (!lchan)
     150    {
     151        VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end");
     152        dtvMonitorRunning = false;
     153        return;
     154    }
     155
     156    R5000Device *dev = lchan->GetR5000Device();
     157
     158    dev->OpenPort();
     159    dev->AddListener(this);
     160
     161    while (dtvMonitorRunning && GetStreamData())
     162        usleep(100000);
     163
     164    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown ");
     165
     166    dev->RemoveListener(this);
     167    dev->ClosePort();
     168
     169    dtvMonitorRunning = false;
     170
     171    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
     172}
     173
     174void R5000SignalMonitor::AddData(const unsigned char *data, uint len)
     175{
     176    if (!dtvMonitorRunning)
     177        return;
     178
     179    if (GetStreamData())
     180        GetStreamData()->ProcessData((unsigned char *)data, len);
     181}
     182
     183/** \fn R5000SignalMonitor::UpdateValues(void)
     184 *  \brief Fills in frontend stats and emits status Qt signals.
     185 *
     186 *   This function uses five ioctl's FE_READ_SNR, FE_READ_SIGNAL_STRENGTH
     187 *   FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain
     188 *   statistics from the frontend.
     189 *
     190 *   This is automatically called by MonitorLoop(), after Start()
     191 *   has been used to start the signal monitoring thread.
     192 */
     193void R5000SignalMonitor::UpdateValues(void)
     194{
     195    if (!running || exit)
     196        return;
     197
     198    if (dtvMonitorRunning)
     199    {
     200        EmitR5000Signals();
     201        if (IsAllGood())
     202            emit AllGood();
     203        // TODO dtv signals...
     204
     205        update_done = true;
     206        return;
     207    }
     208
     209    if (stb_needs_to_wait_for_power &&
     210        (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout))
     211    {
     212        return;
     213    }
     214    stb_needs_to_wait_for_power = false;
     215
     216    R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel);
     217
     218    if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch))
     219    {
     220        bool retried = false;
     221        while (true)
     222        {
     223            R5000Device::PowerState power = fwchan->GetPowerState();
     224            if (R5000Device::kAVCPowerOn == power)
     225            {
     226                AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
     227            }
     228            else if (R5000Device::kAVCPowerOff == power)
     229            {
     230                AddFlags(kFWSigMon_PowerSeen);
     231                fwchan->SetPowerState(true);
     232                stb_wait_for_power_timer.start();
     233                stb_needs_to_wait_for_power = true;
     234            }
     235            else
     236            {
     237                bool qfailed = (R5000Device::kAVCPowerQueryFailed == power);
     238                if (qfailed && !retried)
     239                {
     240                    retried = true;
     241                    continue;
     242                }
     243
     244                VERBOSE(VB_RECORD, "Can't determine if STB is power on, "
     245                        "assuming it is...");
     246                AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
     247            }
     248            break;
     249        }
     250    }
     251
     252    bool isLocked = !HasFlags(kFWSigMon_WaitForPower) ||
     253        HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch);
     254
     255    if (isLocked && stb_needs_retune)
     256    {
     257        fwchan->Retune();
     258        isLocked = stb_needs_retune = false;
     259    }
     260
     261    // Set SignalMonitorValues from info from card.
     262    {
     263        QMutexLocker locker(&statusLock);
     264        signalStrength.SetValue(isLocked ? 100 : 0);
     265        signalLock.SetValue(isLocked ? 1 : 0);
     266    }
     267
     268    EmitR5000Signals();
     269    if (IsAllGood())
     270        emit AllGood();
     271
     272    // Start table monitoring if we are waiting on any table
     273    // and we have a lock.
     274    if (isLocked && GetStreamData() &&
     275        HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT |
     276                   kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
     277                   kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
     278    {
     279        pthread_create(&table_monitor_thread, NULL,
     280                       TableMonitorThread, this);
     281
     282        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
     283                "Waiting for table monitor to start");
     284
     285        while (!dtvMonitorRunning)
     286            usleep(50);
     287
     288        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
     289                "Table monitor started");
     290    }
     291
     292    update_done = true;
     293}
     294
     295#define EMIT(SIGNAL_FUNC, SIGNAL_VAL) \
     296    do { statusLock.lock(); \
     297         SignalMonitorValue val = SIGNAL_VAL; \
     298         statusLock.unlock(); \
     299         emit SIGNAL_FUNC(val); } while (false)
     300
     301/** \fn R5000SignalMonitor::EmitR5000Signals(void)
     302 *  \brief Emits signals for lock, signal strength, etc.
     303 */
     304void R5000SignalMonitor::EmitR5000Signals(void)
     305{
     306    // Emit signals..
     307    EMIT(StatusSignalLock, signalLock);
     308    if (HasFlags(kDTVSigMon_WaitForSig))
     309        EMIT(StatusSignalStrength, signalStrength);
     310}
     311
     312#undef EMIT
  • new file libs/libmythtv/r5000channel.h

    - +  
     1/**
     2 *  R5000Channel
     3 *  Copyright (c) 2008 by Alan Nisota
     4 *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams
     5 *  Distributed as part of MythTV under GPL v2 and later.
     6 */
     7
     8#ifndef _R5000CHANNEL_H_
     9#define _R5000CHANNEL_H_
     10
     11#include "tv_rec.h"
     12#include "dtvchannel.h"
     13#include "r5000device.h"
     14
     15class R5000Channel : public DTVChannel
     16{
     17  public:
     18    R5000Channel(TVRec *parent, const QString &videodevice,
     19                    const QString &_r5ktype);
     20    ~R5000Channel() { Close(); }
     21
     22    // Commands
     23    virtual bool Open(void);
     24    virtual void Close(void);
     25
     26    virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/)
     27        { return false; }
     28    virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/)
     29        { return false; }
     30    virtual bool Retune(void);
     31
     32    // Sets
     33    virtual bool SetChannelByString(const QString &chan);
     34    virtual bool SetChannelByNumber(int channel);
     35    virtual bool SetPowerState(bool on);
     36
     37    // Gets
     38    virtual bool IsOpen(void) const { return isopen; }
     39    virtual R5000Device::PowerState GetPowerState(void) const;
     40    virtual QString GetDevice(void) const;
     41    virtual R5000Device *GetR5000Device(void) { return device; }
     42
     43  protected:
     44    QString            videodevice;
     45    FireWireDBOptions  fw_opts;
     46    R5000Device    *device;
     47    uint               current_channel;
     48    bool               isopen;
     49};
     50
     51#endif // _FIREWIRECHANNEL_H_
  • new file libs/libmythtv/r5000device.h

    - +  
     1/**
     2 *  R5000Device
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7#ifndef _R5000_DEVICE_H_
     8#define _R5000_DEVICE_H_
     9
     10// C++ headers
     11#include <vector>
     12using namespace std;
     13
     14// Qt headers
     15#include <qstring.h>
     16#include <qmutex.h>
     17
     18// MythTV headers
     19#include "streamlisteners.h"
     20
     21extern "C" {
     22#include "r5000/r5000.h"
     23}
     24
     25class TSPacket;
     26class R5kPriv;
     27class R5000Device
     28{
     29  public:
     30
     31    // Public enums
     32    typedef enum
     33    {
     34        kAVCPowerOn,
     35        kAVCPowerOff,
     36        kAVCPowerUnknown,
     37        kAVCPowerQueryFailed,
     38    } PowerState;
     39
     40
     41    // AVC param 0
     42    typedef enum
     43    {
     44        kAVCPowerStateOn           = 0x70,
     45        kAVCPowerStateOff          = 0x60,
     46        kAVCPowerStateQuery        = 0x7f,
     47    } IEEE1394UnitPowerParam0;
     48
     49    R5000Device(int type, QString serial);
     50    ~R5000Device();
     51
     52    bool OpenPort(void);
     53    bool ClosePort(void);
     54    void RunPortHandler(void);
     55
     56    // Commands
     57    virtual bool ResetBus(void) { return false; }
     58
     59    virtual void AddListener(TSDataListener*);
     60    virtual void RemoveListener(TSDataListener*);
     61
     62    // Sets
     63    virtual bool SetPowerState(bool on);
     64    virtual bool SetChannel(const QString &panel_model,
     65                            uint alt_method, uint channel);
     66
     67    // Gets
     68    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; }
     69
     70    // non-const Gets
     71    virtual PowerState GetPowerState(void);
     72
     73    // Statics
     74    static bool IsSTBSupported(const QString &model);
     75    static QString GetModelName(uint vendorid, uint modelid);
     76    static QStringList GetSTBList(void);
     77    static int GetDeviceType(const QString &r5ktype);
     78    void BroadcastToListeners(
     79        const unsigned char *data, uint dataSize);
     80
     81  protected:
     82
     83    bool GetSubunitInfo(uint8_t table[32]);
     84
     85    void SetLastChannel(uint channel);
     86    void ProcessPATPacket(const TSPacket&);
     87    bool StartStreaming(void);
     88    bool StopStreaming(void);
     89
     90    int                      m_type;
     91    QString                  m_serial;
     92    uint                     m_subunitid;
     93    uint                     m_speed;
     94    uint                     m_last_channel;
     95    uint                     m_last_crc;
     96    bool                     m_buffer_cleared;
     97
     98    uint                     m_open_port_cnt;
     99    vector<TSDataListener*>  m_listeners;
     100    mutable QMutex           m_lock;
     101
     102    /// Vendor ID + Model ID to R5000Device STB model string
     103    static QMap<uint64_t,QString> s_id_to_model;
     104    static QMutex                 s_static_lock;
     105private:
     106    r5kdev_t                 *usbdev;
     107    R5kPriv                  *m_priv;
     108};
     109
     110#endif // _FIREWIRE_DEVICE_H_
  • new file libs/libmythtv/r5000recorder.h

    - +  
     1/**
     2 *  R5000Recorder
     3 *  Copyright (c) 2005 by Jim Westfall
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7#ifndef _R5000RECORDER_H_
     8#define _R5000RECORDER_H_
     9
     10// MythTV headers
     11#include "dtvrecorder.h"
     12#include "tspacket.h"
     13#include "streamlisteners.h"
     14
     15class TVRec;
     16class R5000Channel;
     17
     18/** \class R5000Recorder
     19 *  \brief This is a specialization of DTVRecorder used to
     20 *         handle DVB and ATSC streams from a firewire input.
     21 *
     22 *  \sa DTVRecorder
     23 */
     24class R5000Recorder : public DTVRecorder,
     25                         public MPEGSingleProgramStreamListener,
     26                         public TSDataListener
     27{
     28    friend class MPEGStreamData;
     29    friend class TSPacketProcessor;
     30
     31  public:
     32    R5000Recorder(TVRec *rec, R5000Channel *chan);
     33    virtual ~R5000Recorder();
     34
     35    // Commands
     36    bool Open(void);
     37    void Close(void);
     38
     39    void StartStreaming(void);
     40    void StopStreaming(void);
     41
     42    void StartRecording(void);
     43    bool PauseAndWait(int timeout = 100);
     44
     45    void AddData(const unsigned char *data, uint dataSize);
     46    void ProcessTSPacket(const TSPacket &tspacket);
     47
     48    // Sets
     49    void SetOptionsFromProfile(RecordingProfile *profile,
     50                               const QString &videodev,
     51                               const QString &audiodev,
     52                               const QString &vbidev);
     53    void SetStreamData(MPEGStreamData*);
     54
     55    // Gets
     56    MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; }
     57
     58    // MPEG Single Program
     59    void HandleSingleProgramPAT(ProgramAssociationTable*);
     60    void HandleSingleProgramPMT(ProgramMapTable*);
     61
     62  protected:
     63    R5000Recorder(TVRec *rec);
     64
     65  private:
     66    MPEGStreamData        *_mpeg_stream_data;
     67    R5000Channel       *channel;
     68    bool                   isopen;
     69    vector<unsigned char>  buffer;
     70};
     71
     72#endif //  _R5000RECORDER_H_
  • new file libs/libmythtv/r5000signalmonitor.h

    - +  
     1// -*- Mode: c++ -*-
     2
     3#ifndef _R5000SIGNALMONITOR_H_
     4#define _R5000SIGNALMONITOR_H_
     5
     6#include <qmap.h>
     7#include <qmutex.h>
     8#include <qdatetime.h>
     9
     10#include "dtvsignalmonitor.h"
     11#include "firewiredevice.h"
     12#include "util.h"
     13
     14class R5000Channel;
     15
     16class R5000SignalMonitor : public DTVSignalMonitor, public TSDataListener
     17{
     18    Q_OBJECT
     19
     20  public:
     21    R5000SignalMonitor(int db_cardnum, R5000Channel *_channel,
     22                          uint64_t _flags = kFWSigMon_WaitForPower,
     23                          const char *_name = "R5000SignalMonitor");
     24
     25    virtual void HandlePAT(const ProgramAssociationTable*);
     26    virtual void HandlePMT(uint, const ProgramMapTable*);
     27
     28    void Stop(void);
     29
     30  public slots:
     31    void deleteLater(void);
     32
     33  protected:
     34    R5000SignalMonitor(void);
     35    R5000SignalMonitor(const R5000SignalMonitor&);
     36    virtual ~R5000SignalMonitor();
     37
     38    virtual void UpdateValues(void);
     39    void EmitR5000Signals(void);
     40
     41    static void *TableMonitorThread(void *param);
     42    void RunTableMonitor(void);
     43
     44    bool SupportsTSMonitoring(void);
     45
     46    void AddData(const unsigned char *data, uint dataSize);
     47
     48  public:
     49    static const uint kPowerTimeout;
     50    static const uint kBufferTimeout;
     51
     52  protected:
     53    bool               dtvMonitorRunning;
     54    pthread_t          table_monitor_thread;
     55    bool               stb_needs_retune;
     56    bool               stb_needs_to_wait_for_pat;
     57    bool               stb_needs_to_wait_for_power;
     58    MythTimer          stb_wait_for_pat_timer;
     59    MythTimer          stb_wait_for_power_timer;
     60
     61    vector<unsigned char> buffer;
     62
     63    static QMap<void*,uint> pat_keys;
     64    static QMutex           pat_keys_lock;
     65};
     66
     67#endif // _R5000SIGNALMONITOR_H_
  • new file libs/libmythtv/r5000/libusb_augment.c

    - +  
     1// 2005-10-19/lindi: downloaded from http://www.gaesi.org/~nmct/cvista/cvista/
     2
     3// libusb_augment.c
     4// $Revision$
     5// $Date$
     6
     7// Hopefully, the functions in this file will become part of libusb.
     8
     9#include <stdio.h>
     10#include <sys/ioctl.h>
     11#include <errno.h>
     12#include <sys/time.h>
     13#include <sys/poll.h>
     14#include <usb.h>
     15#include <linux/usbdevice_fs.h>
     16#include <string.h>
     17#include <signal.h>
     18#define LIBUSB_AUGMENT
     19#include "libusb_augment.h"
     20
     21// Taken from libusb file usbi.h because usb.h
     22// hides the definition of usb_dev_handle.
     23extern int usb_debug;
     24
     25struct usb_dev_handle {
     26  int fd;
     27
     28  struct usb_bus *bus;
     29  struct usb_device *device;
     30
     31  int config;
     32  int interface;
     33  int altsetting;
     34
     35  /* Added by RMT so implementations can store other per-open-device data */
     36  void *impl_info;
     37};
     38
     39// Taken from libusb file error.h to supply error handling macro definition.
     40typedef enum {
     41  USB_ERROR_TYPE_NONE = 0,
     42  USB_ERROR_TYPE_STRING,
     43  USB_ERROR_TYPE_ERRNO,
     44} usb_error_type_t;
     45
     46extern char usb_error_str[1024];
     47extern usb_error_type_t usb_error_type;
     48
     49#define USB_ERROR_STR(format, args...) \
     50        do { \
     51          usb_error_type = USB_ERROR_TYPE_STRING; \
     52          snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
     53          if (usb_debug >= 2) \
     54            fprintf(stderr, "USB error: %s\n", usb_error_str); \
     55        } while (0)
     56
     57static int urb_signr = 0;
     58void (*urb_completion_callback)(struct usbdevfs_urb *) = NULL;
     59#define USB_ASYNC_COMPLETION_SIGNAL (SIGRTMIN + 5)
     60
     61void urb_completion_handler(int signum, siginfo_t *info, void *context)
     62{
     63   struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr;
     64   struct usbdevfs_urb *context1;
     65   usb_dev_handle *dev = (usb_dev_handle *)urb->usercontext;
     66   int ret;
     67   if (info->si_code != SI_ASYNCIO ||
     68       info->si_signo != USB_ASYNC_COMPLETION_SIGNAL) {
     69       return;
     70   }
     71   if(info->si_errno != 0) {
     72     USB_ERROR_STR("Async URB Completion failed: %s", strerror(info->si_errno));
     73     return;
     74   }
     75   ret = ioctl(dev->fd, USBDEVFS_REAPURB, &context1);
     76   if(ret  < 0) {
     77     USB_ERROR_STR("Failed to read URB: %s", strerror(-ret));
     78     return;
     79   }
     80   if(context1 != urb) {
     81     USB_ERROR_STR("Reaped unexpected urb");
     82     return;
     83   }
     84   if(urb_completion_callback)
     85     urb_completion_callback(urb);
     86}
     87
     88int usbdevfs_urb_signal_completion(void (*cb)( struct usbdevfs_urb *))
     89{
     90  urb_completion_callback = cb;
     91  urb_signr = USB_ASYNC_COMPLETION_SIGNAL;
     92  struct sigaction usb_linux_sa;
     93  usb_linux_sa.sa_sigaction = urb_completion_handler;
     94  sigfillset(&usb_linux_sa.sa_mask);
     95  usb_linux_sa.sa_flags = SA_SIGINFO;
     96  usb_linux_sa.sa_flags |= SA_ONSTACK;
     97  sigaction(USB_ASYNC_COMPLETION_SIGNAL, &usb_linux_sa, NULL);
     98  return 0;
     99}
     100
     101struct usbdevfs_urb *usb_bulk_setup(
     102                struct usbdevfs_urb *iso_urb, // URB pointer-pointer.
     103                unsigned char ep,  // Device endpoint.
     104                char *bytes,       // Data buffer pointer.
     105                int size) {        // Size of the buffer.
     106  struct usbdevfs_urb *local_urb;
     107
     108  // No more than 16384 bytes can be transferred at a time.
     109  if (size > 16384) {
     110    USB_ERROR_STR("error on transfer size: %s", strerror(EINVAL));
     111    return NULL;
     112  }
     113  local_urb = iso_urb;
     114  if (!local_urb) {
     115    local_urb = (struct usbdevfs_urb *) calloc(1, sizeof(struct usbdevfs_urb));
     116    if (!local_urb) {
     117      USB_ERROR_STR("error on packet size: %s", strerror(EINVAL));
     118      return NULL;
     119    }
     120  }
     121  local_urb->type = USBDEVFS_URB_TYPE_BULK;
     122  local_urb->endpoint = ep;
     123  local_urb->status = 0;
     124  local_urb->flags = 0;
     125  local_urb->buffer = bytes;
     126  local_urb->buffer_length = size;
     127  local_urb->actual_length = 0;
     128  local_urb->start_frame = 0;
     129  local_urb->number_of_packets = 0;
     130  local_urb->error_count = 0;
     131  local_urb->signr = urb_signr;
     132  local_urb->usercontext = (void *) 0;
     133  return local_urb;
     134}
     135// Reading and writing are the same except for the endpoint
     136int usb_isochronous_setup(struct usbdevfs_urb **iso_urb, // URB pointer-pointer.
     137                          unsigned char ep,  // Device endpoint.
     138                          int pktsize,       // Endpoint packet size.
     139                          char *bytes,       // Data buffer pointer.
     140                          int size) {        // Size of the buffer.
     141  struct usbdevfs_urb *local_urb;
     142  // int ret
     143  // was unused /lindi
     144  int pktcount, fullpkts, partpktsize, packets, urb_size;
     145
     146  // No more than 32768 bytes can be transferred at a time.
     147  if (size > 32768) {
     148    USB_ERROR_STR("error on transfer size: %s", strerror(EINVAL));
     149    return -EINVAL;
     150  }
     151
     152  // Determine the number of packets that need to be created based upon the
     153  // amount of data to be transferred, and the maximum packet size of the
     154  // endpoint.
     155
     156  // Find integral number of full packets.
     157  //fprintf(stderr, "buf size: %d\n", size);
     158  //fprintf(stderr, "iso size: %d\n", pktsize);
     159  fullpkts = size / pktsize;
     160  //fprintf(stderr, "Number of full packets: %d\n", fullpkts);
     161  // Find length of partial packet.
     162  partpktsize = size % pktsize;
     163  //fprintf(stderr, "Size of partial packet: %d\n", partpktsize);
     164  // Find total number of packets to be transfered.
     165  packets = fullpkts + ((partpktsize > 0) ? 1 : 0);
     166  //fprintf(stderr, "Total number of packets: %d\n", packets);
     167  // Limit the number of packets transfered according to
     168  // the Linux usbdevfs maximum read/write buffer size.
     169  if ((packets < 1) || (packets > 128)) {
     170    USB_ERROR_STR("error on packet size: %s", strerror(EINVAL));
     171    return -EINVAL;
     172  }
     173
     174  // If necessary, allocate the urb and packet
     175  // descriptor structures from the heap.
     176  local_urb = *iso_urb;
     177  if (!local_urb) {
     178    urb_size = sizeof(struct usbdevfs_urb) +
     179      packets * sizeof(struct usb_iso_packet_desc);
     180    local_urb = (struct usbdevfs_urb *) calloc(1, urb_size);
     181    if (!local_urb) {
     182      USB_ERROR_STR("error on packet size: %s", strerror(EINVAL));
     183      return -ENOMEM;
     184    }
     185  }
     186
     187  // Set up each packet for the data to be transferred.
     188  for (pktcount = 0; pktcount < fullpkts; pktcount++) {
     189    local_urb->iso_frame_desc[pktcount].length = pktsize;
     190    local_urb->iso_frame_desc[pktcount].actual_length = 0;
     191    local_urb->iso_frame_desc[pktcount].status = 0;
     192  }
     193
     194  // Set up the last packet for the partial data to be transferred.
     195  if (partpktsize > 0) {
     196    local_urb->iso_frame_desc[pktcount].length = partpktsize;
     197    local_urb->iso_frame_desc[pktcount].actual_length = 0;
     198    local_urb->iso_frame_desc[pktcount++].status = 0;
     199  }
     200
     201  // Set up the URB structure.
     202  local_urb->type = USBDEVFS_URB_TYPE_ISO;
     203  //fprintf(stderr, "type: %d\n", local_urb->type);
     204  local_urb->endpoint = ep;
     205  //fprintf(stderr, "endpoint: 0x%x\n", local_urb->endpoint);
     206  local_urb->status = 0;
     207  local_urb->flags = USBDEVFS_URB_ISO_ASAP; // Additional flags here?
     208  //fprintf(stderr, "flags: %d\n", local_urb->flags);
     209  local_urb->buffer = bytes;
     210  //fprintf(stderr, "buffer: 0x%x\n", local_urb->buffer);
     211  local_urb->buffer_length = size;
     212  //fprintf(stderr, "buffer_length: %d\n", local_urb->buffer_length);
     213  local_urb->actual_length = 0;
     214  local_urb->start_frame = 0;
     215  //fprintf(stderr, "start_frame: %d\n", local_urb->start_frame);
     216  local_urb->number_of_packets = pktcount;
     217  //fprintf(stderr, "number_of_packets: %d\n", local_urb->number_of_packets);
     218  local_urb->error_count = 0;
     219  local_urb->signr = 0;
     220  //fprintf(stderr, "signr: %d\n", local_urb->signr);
     221  local_urb->usercontext = (void *) 0;
     222  *iso_urb = local_urb;
     223  return 0;
     224}
     225
     226
     227int usb_urb_submit(usb_dev_handle *dev,     // Open usb device handle.
     228                   struct usbdevfs_urb *iso_urb,        // Pointer to URB.
     229                   struct timeval *tv_submit) { // Time structure pointer.
     230  int ret;
     231
     232  iso_urb->usercontext = dev;
     233  // Get actual time, of the URB submission.
     234  if(tv_submit)
     235    gettimeofday(tv_submit, NULL);
     236  // Submit the URB through an IOCTL call.
     237  ret = ioctl(dev->fd, USBDEVFS_SUBMITURB, iso_urb);
     238  //fprintf(stderr, "start_frame now: %d\n", iso_urb->start_frame);
     239  //fprintf(stderr, "submit ioctl return value: %d\n", ret);
     240  if (ret < 0) {
     241    //fprintf(stderr, "error submitting URB: %s\n", strerror(errno));
     242    USB_ERROR_STR("error submitting URB: %s", strerror(errno));
     243    return -errno;
     244  }
     245  return ret;
     246}
     247
     248
     249int usb_urb_reap(usb_dev_handle *dev,     // Open usb device handle.
     250                 struct usbdevfs_urb *iso_urb,        // Pointer to URB.
     251                 int timeout) {           // Attempt timeout (usec).
     252  struct timeval tv_ref, tv_msec, tv;
     253  void *context;
     254  int waiting, ret;
     255  struct pollfd ufd[1];
     256
     257  // Get actual time, and add the timeout value. The result is the absolute
     258  // time where we have to quit waiting for an isochronous message.
     259  ufd[0].fd = dev->fd;
     260  ufd[0].events = POLLIN | POLLOUT;
     261  ufd[0].revents = 0;
     262  ret = poll(ufd, 1, timeout);
     263  if(ret <= 0)
     264    return -ETIMEDOUT;
     265
     266  //fprintf(stderr, "preparing to reap\n");
     267  ret = ioctl(dev->fd, USBDEVFS_REAPURB, &context);
     268
     269  /*
     270   * If there was an error, that wasn"t EAGAIN (no completion), then
     271   * something happened during the reaping and we should return that
     272   * error now
     273   */
     274  //fprintf(stderr, "reap ioctl return value: %d\n", ret);
     275  if (ret < 0) {
     276    USB_ERROR_STR("error reaping interrupt URB: %s",
     277                  strerror(errno));
     278    return -errno;
     279  }
     280
     281  //fprintf(stderr, "actual_length: %d\n", iso_urb->actual_length);
     282  //fprintf(stderr, "URB status: %d\n", iso_urb->status);
     283  //fprintf(stderr, "error count: %d\n", iso_urb->error_count);
     284
     285  //fprintf(stderr, "waiting done\n");
     286  if(iso_urb != context) {
     287    fprintf(stderr, "Expected urb: %p but got %p\n", iso_urb, context);
     288    return -1;
     289  }
     290  //fprintf(stderr, "Total bytes: %d\n", bytesdone);
     291  return iso_urb->actual_length;
     292}
     293
     294int usb_urb_cancel(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb)
     295{
     296  return ioctl(dev->fd, USBDEVFS_DISCARDURB, iso_urb);
     297}
  • new file libs/libmythtv/r5000/libusb_augment.h

    - +  
     1// libusb_augment.h
     2// $Revision$
     3// $Date$
     4
     5#ifdef LIBUSB_AUGMENT
     6// Taken from libusb file linux.h to provide the URB structure definitions.
     7struct usb_iso_packet_desc {
     8  unsigned int length;
     9  unsigned int actual_length;
     10  unsigned int status;
     11};
     12#endif
     13
     14int usbdevfs_urb_signal_completion(void (*cb)( struct usbdevfs_urb *));
     15struct usbdevfs_urb *usb_bulk_setup(struct usbdevfs_urb *iso_urb, unsigned char ep,
     16                   char *bytes, int size);
     17int usb_isochronous_setup(struct usbdevfs_urb **iso_urb, unsigned char ep,
     18                          int pktsize, char *bytes, int size);
     19int usb_urb_submit(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb,
     20                   struct timeval *tv_rsubmit);
     21int usb_urb_reap(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb,
     22                 int timeout_usec);
     23int usb_urb_cancel(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb);
  • new file libs/libmythtv/r5000/r5000.c

    - +  
     1#include <stdio.h>
     2#include <sys/types.h>
     3#include <sys/stat.h>
     4#include <fcntl.h>
     5#include <string.h>
     6#include <errno.h>
     7
     8#ifdef R5K_DEBUG
     9char strmfile[256] = "/tmp/strm";
     10int fd = -1;
     11#endif
     12
     13#ifdef R5K_RAWUSB
     14int usbfd = -1;
     15#endif
     16#include "r5000_internal.h"
     17#include "libusb_augment.h"
     18#include "r5000init.h"
     19
     20#define R5K_WARM_VID 0x0547
     21#define R5K_WARM_PID 0x1002
     22
     23#define MAX_URBS_IN_FLIGHT 128
     24#define R5K_URB_BUFFER_SIZE (1 << 14)
     25
     26static int r5000_usb_init = 0;
     27enum {
     28  R5K_PMT_START = 0x01,
     29  R5K_PMT_READY = 0x02
     30};
     31
     32int r5000_create_urbs(r5kdev_t *r5kdev)
     33{
     34  int i;
     35  r5kdev->urbs = (struct usbdevfs_urb *)malloc(sizeof(struct usbdevfs_urb) * MAX_URBS_IN_FLIGHT);
     36  r5kdev->buffer = malloc(R5K_URB_BUFFER_SIZE * MAX_URBS_IN_FLIGHT);
     37  for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) {
     38    usb_bulk_setup(&r5kdev->urbs[i], 0x82, r5kdev->buffer + (R5K_URB_BUFFER_SIZE*i), R5K_URB_BUFFER_SIZE);
     39  }
     40  r5kdev->nexturb = 0;
     41  return 1;
     42}
     43
     44int r5000_free_urbs(r5kdev_t *r5kdev)
     45{
     46  free(r5kdev->urbs);
     47  free(r5kdev->buffer);
     48  return 0;
     49}
     50
     51usb_dev_handle *r5000_locate_device(
     52    unsigned short vendor_id, unsigned short product_id, int skip)
     53{
     54  struct usb_bus *bus;
     55  struct usb_device *dev;
     56  usb_dev_handle *device_handle = 0;
     57  usb_find_busses();
     58  usb_find_devices();
     59
     60  for (bus = usb_get_busses(); bus && !device_handle; bus = bus->next)
     61  {
     62    for (dev = bus->devices; dev && !device_handle; dev = dev->next)
     63    {
     64      if (dev->descriptor.idVendor == vendor_id &&
     65          dev->descriptor.idProduct == product_id)
     66      {
     67        device_handle = usb_open(dev);
     68        if(device_handle && skip) {
     69          usb_close(device_handle);
     70          device_handle = NULL;
     71          skip--;
     72        }
     73      }
     74    }
     75  }
     76
     77  if (device_handle) {
     78    int open_status = usb_set_configuration(device_handle,1);
     79
     80    open_status = usb_claim_interface(device_handle,0);
     81
     82    open_status = usb_set_altinterface(device_handle,0);
     83  }
     84  return (device_handle);
     85}
     86
     87int r5000_init(r5kdev_t *r5kdev) {
     88  int i, bytes;
     89  unsigned char *ptr, *serial = r5kdev->serial;
     90  unsigned char datain[0x80];
     91  bytes = usb_bulk_read(r5kdev->handle, 129, datain, sizeof(datain), 5000);
     92  for(i = 0; i < R5K_INIT_SERIAL; i++) {
     93    PRINTHEX("Write:\n", r5kinit[i].data, r5kinit[i].wlen);
     94    if(r5kinit[i].wsleep) usleep(r5kinit[i].wsleep);
     95    usb_bulk_write(r5kdev->handle, 1, r5kinit[i].data, r5kinit[i].wlen, 5000);
     96    if(r5kinit[i].rsleep) usleep(r5kinit[i].rsleep);
     97    bytes = usb_bulk_read(r5kdev->handle, 129, datain, sizeof(datain), 5000);
     98    PRINTHEX("Read:\n", datain, bytes);
     99    if(r5kinit[i].rlen > 0 && bytes != r5kinit[i].rlen) {
     100      fprintf(stderr, "R5000 initialization failed at stage %d:\n\tExpected %d bytes, but got %d bytes\n", i, r5kinit[i].rlen, bytes);
     101      return 0;
     102    }
     103  }
     104
     105  //last read is serial #
     106  if (datain[0] != 0x08) {
     107    fprintf(stderr, "R5000 initialization failed reading serial #\n");
     108    return 0;
     109  }
     110  for(ptr = datain + 6; ptr < datain + 13; ptr++) {
     111    *serial++ = ( *ptr >= '0' && *ptr <= 'z' ) ? *ptr : '*';
     112  }
     113  *serial = 0;
     114
     115  //complete initialization now
     116  for(; i < R5K_INIT_MAX; i++) {
     117    PRINTHEX("Write:\n", r5kinit[i].data, r5kinit[i].wlen);
     118    if(r5kinit[i].wsleep) usleep(r5kinit[i].wsleep);
     119    usb_bulk_write(r5kdev->handle, 1, r5kinit[i].data, r5kinit[i].wlen, 5000);
     120    if(r5kinit[i].rsleep) usleep(r5kinit[i].rsleep);
     121    bytes = usb_bulk_read(r5kdev->handle, 129, datain, sizeof(datain), 5000);
     122    PRINTHEX("Read:\n", datain, bytes);
     123    if(r5kinit[i].rlen > 0 && bytes != r5kinit[i].rlen) {
     124      fprintf(stderr, "R5000 initialization failed at stage %d:\n\tExpected %d bytes, but got %d bytes\n", i, r5kinit[i].rlen, bytes);
     125      return 0;
     126    }
     127  }
     128  return 1;
     129}
     130
     131int r5000_start_stream(r5kdev_t *r5kdev)
     132{
     133  unsigned char data[0x80];
     134  int bytes;
     135  int i;
     136  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle;
     137
     138  if(! r5kdev->urbs)
     139    r5000_create_urbs(r5kdev);
     140
     141  data[0] = 0x30;
     142  usb_bulk_write(handle, 1, data, 1, 5000);
     143  bytes = usb_bulk_read(handle, 129, data, 2, 5000);
     144
     145  //0x50 sets byte mode.  Use '0x60' to set word mode
     146  data[0] = r5kdev->read_words ? 0x60: 0x50;
     147  usb_bulk_write(handle, 1, data, 1, 5000);
     148
     149  for(i=0; i < MAX_URBS_IN_FLIGHT; i++) {
     150    usb_urb_submit(handle, &r5kdev->urbs[i], NULL);
     151  }
     152  r5kdev->nexturb = 0;
     153  r5kdev->streaming = 1;
     154  if(r5kdev->start_stream)
     155    r5kdev->start_stream(r5kdev);
     156  return 1;
     157}
     158
     159int r5000_stop_stream(r5kdev_t *r5kdev)
     160{
     161  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle;
     162  struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs;
     163  int i;
     164
     165  if(r5kdev->streaming) {
     166    for(i=0; i < MAX_URBS_IN_FLIGHT; i++)
     167      usb_urb_cancel(handle, &urbs[i]);
     168    r5kdev->streaming = 0;
     169  }
     170  return 1;
     171}
     172
     173r5kdev_t *r5000_open(r5ktype_t type,
     174                     unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data),
     175                     void *cb_data,
     176                     const char *serial)
     177{
     178  r5kdev_t *r5kdev, r5kd;
     179  struct usb_dev_handle *handle;
     180  int count = 0;
     181  memset(&r5kd, 0, sizeof(r5kdev_t));
     182
     183  if(! r5000_usb_init) {
     184    int bus_count, dev_count;
     185    usb_init();
     186    bus_count = usb_find_busses();
     187    dev_count = usb_find_devices();
     188    if(bus_count == 0 || dev_count ==0) {
     189      fprintf(stderr, "R5000 failed to locate any R5000 devices.  Are you sure you have permissions set properly?\n");
     190      return NULL;
     191    }
     192    r5000_usb_init = 1;
     193  }
     194#ifdef R5K_DEBUG
     195  fd = open(strmfile, O_RDONLY);
     196#endif
     197#ifdef R5K_RAWUSB
     198  usbfd = open("raw.av", O_WRONLY | O_CREAT | O_TRUNC);
     199#endif
     200  while(count < R5K_MAX_DEVS) {
     201    r5kd.handle = r5000_locate_device(R5K_WARM_VID, R5K_WARM_PID, count);
     202    if(! r5kd.handle)
     203      return NULL;
     204    if (! r5000_init(&r5kd)) {
     205      usb_close(r5kd.handle);
     206      return NULL;
     207    }
     208    if(! serial || memcmp(serial, r5kd.serial, 8) == 0)
     209      break;
     210    count++;
     211    usb_close(r5kd.handle);
     212  }
     213  r5kdev = (r5kdev_t *)malloc(sizeof(r5kdev_t));
     214  *r5kdev = r5kd;
     215  r5kdev->urbs = NULL;
     216  r5kdev->cb = cb;
     217  r5kdev->cb_data = cb_data;
     218  switch(type) {
     219    case R5K_STB_VIP:
     220      vip_init(r5kdev);
     221      r5kdev->stb_type = R5K_STB_VIP;
     222      break;
     223    case R5K_STB_DIRECTV:
     224      directv_init(r5kdev);
     225      r5kdev->stb_type = R5K_STB_DIRECTV;
     226      break;
     227    case R5K_STB_DSR:
     228    case R5K_STB_HDD:
     229      sat_init(r5kdev, type);
     230      r5kdev->stb_type = type;
     231      break;
     232    default:
     233      fprintf(stderr, "Unknown STB type %d specified.\n", type);
     234      vip_init(r5kdev);
     235      r5kdev->stb_type = R5K_STB_VIP;
     236      break;
     237  }
     238  return r5kdev;
     239}
     240
     241int r5000_close(r5kdev_t *r5kdev)
     242{
     243  if(! r5kdev)
     244    return 1;
     245  if(r5kdev->urbs) {
     246    if(r5kdev->streaming)
     247      r5000_stop_stream(r5kdev);
     248    r5000_free_urbs(r5kdev);
     249  }
     250  usb_close(r5kdev->handle);
     251#ifdef R5K_RAWUSB
     252  if(usbfd >= 0) close(usbfd);
     253#endif
     254  switch(r5kdev->stb_type) {
     255    case R5K_STB_VIP:
     256      vip_free(r5kdev);
     257      break;
     258    case R5K_STB_DIRECTV:
     259      directv_free(r5kdev);
     260      break;
     261    case R5K_STB_DSR:
     262    case R5K_STB_HDD:
     263      sat_free(r5kdev);
     264      break;
     265  }
     266  free(r5kdev);
     267  return 1;
     268}
     269
     270int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec)
     271{
     272  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle;
     273  struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs;
     274  int len;
     275  unsigned char *buf;
     276  if(! r5kdev->streaming)
     277    return -1;
     278  len = usb_urb_reap(handle, &urbs[r5kdev->nexturb], timeout_usec);
     279  if(len <= 0) {
     280    if(len != -ETIMEDOUT)
     281      fprintf(stderr, "(%d) Reap failed at %08x: %s\n", r5kdev->nexturb, r5kdev->bytes_read, strerror(errno));
     282    return len;
     283  }
     284  buf = r5kdev->buffer + (R5K_URB_BUFFER_SIZE*r5kdev->nexturb);
     285#ifdef R5K_RAWUSB
     286  if(usbfd >= 0) write(usbfd, buf, len);
     287#endif
     288#ifdef R5K_DEBUG
     289  if(fd >= 0)
     290    len = read(fd, buf, len);
     291#endif
     292  r5kdev->process_block(r5kdev, buf, len);
     293  r5kdev->bytes_read += len;
     294  usb_urb_submit(handle, &urbs[r5kdev->nexturb], NULL);
     295  r5kdev->nexturb = (r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT;
     296  return 0;
     297}
     298
     299//use this to read a status frame.  It doesn't do anything special
     300//but makes it obvious what data is expected
     301int r5000_read_status(r5kdev_t *r5kdev, unsigned char *buf)
     302{
     303  return usb_bulk_read(r5kdev->handle, 129, buf, 128, 5000);
     304}
     305
     306int r5000_get_power_state(r5kdev_t *r5kdev)
     307{
     308  unsigned char data1[1]  = { 0x30 };
     309  unsigned char data2[0x80];
     310  int count = 10;
     311  while(count--) {
     312    r5000_read_status(r5kdev, data2);
     313    usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000);
     314    usleep(100000);
     315    if(usb_bulk_read(r5kdev->handle, 1, data2, 2, 5000) == 2 &&
     316       data2[0] == 0x0a && (data2[1] & 0x4e) == 0x4c)
     317      return (!!(data2[1] == 0x4d));
     318    usleep(100000);
     319  }
     320  fprintf(stderr, "R5000 failed to read power state.  Assuming ON state\n");
     321  return 1;
     322}
     323
     324int r5000_toggle_on_off(r5kdev_t *r5kdev)
     325{
     326  unsigned char data1[1]  = { 0x30 };
     327  unsigned char data3[0x80], on_off, new_state;
     328  int len;
     329  int count = 20;
     330  on_off = r5000_get_power_state(r5kdev);
     331  if(! r5kdev->button) {
     332    fprintf(stderr, "No button IR commands defined for this device!\n");
     333    return on_off;
     334  }
     335  //fprintf(stderr, "Start state: %s\n", on_off ? "On" : "Off");
     336  usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000);
     337  usleep(100000);
     338  usb_bulk_write(r5kdev->handle, 1, r5kdev->button->power, r5kdev->button->len, 5000);
     339  usleep(100000);
     340  len = usb_bulk_read(r5kdev->handle, 1, data3, 2, 5000);
     341  usleep(100000);
     342  while(count-- && (new_state = r5000_get_power_state(r5kdev)) == on_off)
     343    usleep(100000);
     344  //fprintf(stderr, "End state: %s\n", !on_off ? "On" : "Off");
     345  return new_state;
     346}
     347
     348int r5000_change_channel(r5kdev_t *r5kdev, int chan)
     349{
     350  int pos = 1000000, digit;
     351  unsigned char data2[0x80];
     352  unsigned char *ptr;
     353  if(! r5kdev->button) {
     354    fprintf(stderr, "No button IR commands defined for this device!\n");
     355    return;
     356  }
     357  r5000_read_status(r5kdev, data2);
     358  usb_bulk_write(r5kdev->handle, 1, r5kdev->button->clear, r5kdev->button->len, 5000);
     359  usleep(r5kdev->button->delay);
     360  while(pos != 0 && (chan/pos) == 0)
     361    pos /= 10;
     362  if(pos == 0)
     363    pos = 1;
     364  while(pos != 0) {
     365    digit = chan / pos;
     366    switch(digit) {
     367      case 0 : ptr = r5kdev->button->b0; break;
     368      case 1 : ptr = r5kdev->button->b1; break;
     369      case 2 : ptr = r5kdev->button->b2; break;
     370      case 3 : ptr = r5kdev->button->b3; break;
     371      case 4 : ptr = r5kdev->button->b4; break;
     372      case 5 : ptr = r5kdev->button->b5; break;
     373      case 6 : ptr = r5kdev->button->b6; break;
     374      case 7 : ptr = r5kdev->button->b7; break;
     375      case 8 : ptr = r5kdev->button->b8; break;
     376      case 9 : ptr = r5kdev->button->b9; break;
     377    }
     378    usb_bulk_write(r5kdev->handle, 1, ptr, r5kdev->button->len, 5000);
     379    chan -= digit*pos;
     380    pos/= 10;
     381    usleep(r5kdev->button->delay);
     382  }
     383  usb_bulk_write(r5kdev->handle, 1, r5kdev->button->enter, r5kdev->button->len, 5000);
     384  r5kdev->channel = chan;
     385  return 1;
     386}
     387
     388int r5000_find_stbs(r5kenum_t *devs)
     389{
     390  r5kdev_t r5kdev;
     391  devs->count = 0;
     392  if(! r5000_usb_init) {
     393    int bus_count, dev_count;
     394    usb_init();
     395    bus_count = usb_find_busses();
     396    dev_count = usb_find_devices();
     397    if(bus_count == 0 || dev_count ==0) {
     398      fprintf(stderr, "R5000 failed to locate any R5000 devices.  Are you sure you have permissions set properly?\n");
     399      return 0;
     400    }
     401    r5000_usb_init = 1;
     402  }
     403  while(devs->count < R5K_MAX_DEVS) {
     404    r5kdev.handle = r5000_locate_device(R5K_WARM_VID, R5K_WARM_PID, devs->count);
     405    if(! r5kdev.handle)
     406      break;
     407    if(! r5000_init(&r5kdev)) {
     408      usb_close(r5kdev.handle);
     409      return 0;
     410    }
     411    memcpy(devs->serial[devs->count], r5kdev.serial, 8);
     412    devs->count++;
     413    usb_close(r5kdev.handle);
     414  }
     415  return 1;
     416}
  • new file libs/libmythtv/r5000/r5000.h

    - +  
     1#ifndef R5000_H
     2#define R5000_H
     3
     4#ifndef r5kdev_t
     5#define r5kdev_t void
     6#endif
     7
     8#define R5K_MAX_DEVS 10
     9typedef struct {
     10  unsigned char serial[R5K_MAX_DEVS][8];
     11  int count;
     12} r5kenum_t;
     13
     14typedef enum {
     15  R5K_STB_VIP = 0,
     16  R5K_STB_DIRECTV,
     17  R5K_STB_HDD,
     18  R5K_STB_DSR,
     19  R5K_STB_MAX,
     20} r5ktype_t;
     21
     22extern r5kdev_t *r5000_open(r5ktype_t type, unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, const char *serial);
     23extern int r5000_close(r5kdev_t *r5kdev);
     24extern int r5000_start_stream(r5kdev_t *r5kdev);
     25extern int r5000_stop_stream(r5kdev_t *r5kdev);
     26extern int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec);
     27extern int r5000_get_power_state(r5kdev_t *r5kdev);
     28extern int r5000_toggle_on_off(r5kdev_t *r5kdev);
     29extern int r5000_change_channel(r5kdev_t *r5kdev, int chan);
     30extern int r5000_find_stbs(r5kenum_t *devs);
     31#endif //R5000_H
  • new file libs/libmythtv/r5000/r5000_internal.h

    - +  
     1#ifndef R5000_INT_H
     2#define R5000_INT_H
     3
     4#include <usb.h>
     5#include <linux/usbdevice_fs.h>
     6
     7#define PRINTHEX(str, data, len) if(0) do { \
     8  int _i; \
     9  fprintf(stderr, str); \
     10  for(_i = 0; _i < (len); _i++) { \
     11    fprintf(stderr, "%02x ", (data)[_i]); \
     12    if((_i % 16) == 15) fprintf(stderr, "\n"); \
     13  } \
     14  if(_i % 16) fprintf(stderr, "\n"); \
     15} while(0)
     16
     17#define R5K_MAX_BUTTON_SIZE 0x80
     18#define R5K_MAX_PIDS 10
     19#define IS_VIDEO(x) ((x) == 0x02 || (x) == 0x1b)
     20
     21struct r5k_descriptor {
     22  unsigned char d[10];
     23};
     24
     25struct r5k_epid {
     26  int pid;
     27  unsigned char id;
     28  struct r5k_descriptor desc;
     29};
     30
     31struct r5000_buttons {
     32  int len;
     33  int delay;
     34  unsigned char b0[R5K_MAX_BUTTON_SIZE];
     35  unsigned char b1[R5K_MAX_BUTTON_SIZE];
     36  unsigned char b2[R5K_MAX_BUTTON_SIZE];
     37  unsigned char b3[R5K_MAX_BUTTON_SIZE];
     38  unsigned char b4[R5K_MAX_BUTTON_SIZE];
     39  unsigned char b5[R5K_MAX_BUTTON_SIZE];
     40  unsigned char b6[R5K_MAX_BUTTON_SIZE];
     41  unsigned char b7[R5K_MAX_BUTTON_SIZE];
     42  unsigned char b8[R5K_MAX_BUTTON_SIZE];
     43  unsigned char b9[R5K_MAX_BUTTON_SIZE];
     44  unsigned char clear[R5K_MAX_BUTTON_SIZE];
     45  unsigned char enter[R5K_MAX_BUTTON_SIZE];
     46  unsigned char power[R5K_MAX_BUTTON_SIZE];
     47};
     48
     49struct r5kdev {
     50  usb_dev_handle *handle;
     51  unsigned char serial[8];
     52  struct usbdevfs_urb *urbs;
     53  unsigned char *buffer;
     54  int stb_type;
     55  int read_words;
     56  void (*process_block)(struct r5kdev *r5kdev, unsigned char *buf, int len);
     57  void (*start_stream)(struct r5kdev *r5kdev);
     58  void *stbdata;
     59  unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data);
     60  void *cb_data;
     61  int nexturb;
     62  int streaming;
     63  int bytes_read;
     64  struct r5000_buttons *button;
     65  int channel;
     66  unsigned char pmt_pkt[188];
     67  unsigned char num_pmt_entries;
     68  unsigned char pmt_state;
     69  unsigned char pmt_next_cc;
     70  struct r5k_epid pmt[R5K_MAX_PIDS];
     71} r5kdev_t;
     72#define r5kdev_t struct r5kdev
     73
     74#include "r5000.h"
     75
     76extern unsigned char r5000_pat_pkt[188];
     77extern struct r5k_descriptor r5000_pmt_audio_desc;
     78extern struct r5k_descriptor r5000_pmt_video_desc;
     79extern void r5000_send_pmt(r5kdev_t *r5kdev);
     80
     81//Support for all DirecTV boxes
     82extern void directv_init(r5kdev_t *r5kdev);
     83extern void directv_free(r5kdev_t *r5kdev);
     84
     85//Support for ViP series Dish Network boxes
     86extern void vip_init(r5kdev_t *r5kdev);
     87extern void vip_free(r5kdev_t *r5kdev);
     88
     89//Support for HDD and DSR series satellite/cable boxes
     90extern void sat_init(r5kdev_t *r5kdev, r5ktype_t type);
     91extern void sat_free(r5kdev_t *r5kdev);
     92
     93#endif
  • new file libs/libmythtv/r5000/r5k_vip.c

    - +  
     1//Support for Dish Network ViP211/ViP422 boxes
     2#include <stdio.h>
     3#include <string.h>
     4#include "r5000_internal.h"
     5
     6struct r5000_vip {
     7  unsigned char leftover[188];
     8  int offset;
     9};
     10
     11struct r5000_buttons vip_button_cmd =
     12{
     130x40, //len
     14400000, //delay
     15//button 0:
     16{
     17 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
     18 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     19 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
     20 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     21},
     22//button 1:
     23{
     24 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     25 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     26 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
     27 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     28},
     29//button 2:
     30{
     31 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     32 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     33 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
     34 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     35},
     36//button 3:
     37{
     38 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     39 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     40 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
     41 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     42},
     43//button 4:
     44{
     45 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
     46 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     47 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     48 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     49},
     50//button 5:
     51{
     52 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
     53 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     54 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     55 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     56},
     57//button 6:
     58{
     59 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
     60 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     61 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     62 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     63},
     64//button 7:
     65{
     66 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
     67 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     68 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     69 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     70},
     71//button 8:
     72{
     73 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
     74 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     75 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     76 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     77},
     78//button 9:
     79{
     80 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e,
     81 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     82 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e,
     83 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     84},
     85//Clear:
     86{
     87 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
     88 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     89 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
     90 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     91},
     92//Enter:
     93{
     94 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a,
     95 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     96 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a,
     97 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     98},
     99//Power
     100{
     101 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
     102 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a,
     103 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a,
     104 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e,
     105}
     106};
     107
     108void vip_add_pmt(r5kdev_t *r5kdev, int pid, int table_id)
     109{
     110  int i;
     111  int is_video = IS_VIDEO(table_id);
     112
     113  for(i = 0; i < r5kdev->num_pmt_entries; i++) {
     114    if(r5kdev->pmt[i].pid == pid) {
     115      if(r5kdev->pmt[i].id == table_id)
     116        return;
     117      //different table_id for existing pid.  Reset
     118      r5kdev->num_pmt_entries = 0;
     119      r5kdev->pmt_state = 0;
     120      r5kdev->pmt_pkt[0] = 0;
     121      break;
     122    }
     123    if(is_video) {
     124      if(IS_VIDEO(r5kdev->pmt[i].id)) {
     125        //a video entry already exists.  Reset
     126        r5kdev->num_pmt_entries = 0;
     127        r5kdev->pmt_state = 0;
     128        r5kdev->pmt_pkt[0] = 0;
     129        break;
     130      }
     131    }
     132  }
     133  //Didn't find this PID, add it
     134  if(i == R5K_MAX_PIDS)
     135    return;
     136  printf("Adding %04x: %02x @ %08x\n", pid, table_id, r5kdev->bytes_read);
     137  r5kdev->pmt[r5kdev->num_pmt_entries].pid = pid;
     138  r5kdev->pmt[r5kdev->num_pmt_entries].id  = table_id;
     139  r5kdev->pmt[r5kdev->num_pmt_entries].desc = is_video ? r5000_pmt_video_desc : r5000_pmt_audio_desc;
     140  r5kdev->num_pmt_entries++;
     141  r5kdev->pmt_state |= is_video ? 0x01 : 0x02;
     142}
     143
     144void vip_force_pmt(r5kdev_t *r5kdev, unsigned char *buf)
     145{
     146  int stream_id, pid, afc, af_size = 0;
     147  pid = ((buf[1] << 8) | buf[2]) & 0x1fff;
     148  if(pid == 0x1fff)
     149    return;
     150  if(pid == 0) {
     151    r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
     152    if(r5kdev->pmt_state == 0x03)
     153      r5000_send_pmt(r5kdev);
     154  } else {
     155    if(pid != 0x21)
     156      r5kdev->cb(buf, 188, r5kdev->cb_data);
     157    //Only interested in PES packets starting in this TS packet
     158    if (!buf[1] & 0x40)
     159      return;
     160    afc = (buf[3]>>4) & 0x03;
     161    if(afc == 0x2)
     162      return;
     163    if(afc == 0x3)
     164      af_size = buf[4]+1;
     165    if(buf[4+af_size] != 0x00 || buf[5+af_size] != 0x00 || buf[6+af_size] != 0x01)
     166      return;
     167    //We have a PES packet
     168    stream_id = buf[7+af_size];
     169    if((stream_id & 0xf0) == 0xe0) {
     170      //Video stream (we need the adaptation field)
     171      if(afc != 0x03)
     172        return;
     173      if(0) {
     174        int i;
     175        for(i = 0; i < af_size+8; i++) {
     176          printf("%02x ", buf[i]);
     177          if((i %16) == 15)
     178            printf("\n");
     179        }
     180        printf("\n");
     181      }
     182      if(buf[5] & 0x02) {
     183        // Has private data, this is MPEG4
     184        vip_add_pmt(r5kdev, pid, 0x1b);
     185      } else if(buf[5] & 0x10) {
     186        // Has PCR and no private data, this is MPEG2
     187        vip_add_pmt(r5kdev, pid, 0x02);
     188      }
     189    } else if((stream_id & 0xf0) == 0xc0) {
     190      //Audio stream
     191      vip_add_pmt(r5kdev, pid, 0x04);
     192    } else if(stream_id  == 0xbd) {
     193      //Audio stream
     194      vip_add_pmt(r5kdev, pid, 0x81);
     195    }
     196  }
     197}
     198
     199static void vip_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len)
     200{
     201  struct r5000_vip *vip = (struct r5000_vip *)r5kdev->stbdata;
     202
     203  int pos;
     204  int sync = 1;
     205  if(! r5kdev->streaming)
     206    return;
     207  if(len <= 0)
     208    return;
     209
     210  pos = vip->offset;
     211  while(pos < len) {
     212      if(buf[pos] != 0x47 || (pos <len-1 && buf[pos+1] == 0xff))
     213        goto nosync;
     214      // If we get here, buf[pos] == 0x47
     215      if(vip->offset) {
     216        //previous data exists and is part of a good packet
     217        memcpy(vip->leftover+188-vip->offset, buf, vip->offset);
     218        vip_force_pmt(r5kdev, vip->leftover);
     219        vip->offset = 0;
     220      }
     221      if(pos+188 < len) {
     222        //at least one full packet is available
     223        if(buf[pos+188] != 0x47)
     224          goto nosync;
     225      } else {
     226        //Out of data, but the partial packet may be ok.
     227        memcpy(vip->leftover, buf+pos, len-pos);
     228        vip->offset = 188-(len-pos);
     229        break;
     230      }
     231      //If we get here, we have a good packet
     232      vip_force_pmt(r5kdev, buf+pos);
     233      if(! sync)
     234        printf("(%d) Found sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos);
     235      sync = 1;
     236      pos+=188;
     237      continue;
     238  nosync:
     239      vip->offset=0;
     240      if(sync)
     241        printf("(%d)Lost sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos);
     242      sync = 0;
     243      pos++;
     244  }
     245}
     246
     247static void vip_start_stream(r5kdev_t *r5kdev)
     248{
     249  struct r5000_vip *vip = (struct r5000_vip *)r5kdev->stbdata;
     250  vip->offset = 0;
     251}
     252
     253void vip_init(r5kdev_t *r5kdev)
     254{
     255  struct r5000_vip *vip = (struct r5000_vip *)malloc(sizeof(struct r5000_vip));
     256  r5kdev->stbdata = vip;
     257  r5kdev->process_block = vip_process_block;
     258  r5kdev->start_stream  = vip_start_stream;
     259  r5kdev->button = &vip_button_cmd;
     260}
     261
     262void vip_free(r5kdev_t *r5kdev)
     263{
     264  free(r5kdev->stbdata);
     265}
     266
  • new file libs/libmythtv/r5000/r5k_directv.c

    - +  
     1//Support for DirecTV boxes
     2#include <netinet/in.h>
     3#include <string.h>
     4
     5#include "r5000_internal.h"
     6
     7#define DTV_VPID 0x1322
     8#define DTV_APID 0x1333
     9#define DTV_PAT_PMT_COUNT 5000
     10
     11struct r5000_dtv {
     12  unsigned char vbuf[188*2+4];
     13  unsigned char abuf[188*2+6];
     14  unsigned char *video;
     15  unsigned char *audio;
     16  unsigned int vpos;
     17  unsigned int apos;
     18  unsigned int vstart;
     19  unsigned int astart;
     20  unsigned int video_cc;
     21  unsigned int audio_cc;
     22  unsigned int vstate;
     23  unsigned int pic_pos;
     24  int alen;
     25  unsigned int pat_pmt_count;
     26};
     27
     28struct r5000_buttons directv_button_cmd =
     29{
     300x49, //len
     31400000, //delay
     32//button 0:
     33{
     34    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     35    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     36    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
     37    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     38    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     39},
     40//button 1:
     41{
     42    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     43    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     44    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
     45    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     46    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     47},
     48//button 2:
     49{
     50    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     51    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     52    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
     53    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
     54    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     55},
     56//button 3:
     57{
     58    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     59    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     60    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
     61    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
     62    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     63},
     64//button 4:
     65{
     66    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     67    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     68    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
     69    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
     70    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     71},
     72//button 5:
     73{
     74    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     75    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     76    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
     77    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
     78    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     79},
     80//button 6:
     81{
     82    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     83    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     84    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     85    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
     86    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     87},
     88//button 7:
     89{
     90    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     91    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     92    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     93    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
     94    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     95},
     96//button 8:
     97{
     98    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     99    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     100    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     101    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05,
     102    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     103},
     104//button 9:
     105{
     106    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     107    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     108    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     109    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05,
     110    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     111},
     112//Clear:
     113{
     114    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     115    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     116    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f,
     117    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
     118    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     119},
     120//Enter:
     121{
     122    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     123    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     124    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f,
     125    0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05,
     126    0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     127},
     128//Power
     129{
     130    0x00, 0x43, 0x0a, 0x80, 0xca, 0x00, 0x5a, 0x2d, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f,
     131    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     132    0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05,
     133    0x05, 0x0f, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x05, 0x05, 0x05, 0x0f,
     134    0x05, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x0f, 0x05,
     135}
     136};
     137
     138static int directv_make_empty_pes(unsigned char *ptr, unsigned char type)
     139{
     140  ptr[0] = 0x00;
     141  ptr[1] = 0x00;
     142  ptr[2] = 0x01;
     143  ptr[3] = type;
     144  ptr[4] = 0x00;
     145  ptr[5] = 0x00;
     146  ptr[6] = 0x80;
     147  ptr[7] = 0x00; //2 MSB represent PTS/DTS flag
     148  ptr[8] = 0x0a;
     149  ptr[9]  = 0xff;
     150  ptr[10] = 0xff;
     151  ptr[11] = 0xff;
     152  ptr[12] = 0xff;
     153  ptr[13] = 0xff;
     154  ptr[14] = 0xff;
     155  ptr[15] = 0xff;
     156  ptr[16] = 0xff;
     157  ptr[17] = 0xff;
     158  ptr[18] = 0xff;
     159  return 19;
     160}
     161
     162static void directv_make_pespts(unsigned char *outptr, unsigned int pts)
     163{
     164        pts = htonl(pts);
     165        unsigned char *inpts = (unsigned char *)&pts;
     166        outptr[0] = 0x01 |
     167                    ((inpts[0] & 0xC0) >>5);
     168        outptr[1] = ((inpts[0] & 0x3F) << 2) |
     169                    ((inpts[1] & 0xC0) >> 6);
     170        outptr[2] = 0x01 | ((inpts[1] & 0x3F) << 2) |
     171                    ((inpts[2] & 0x80) >> 6);
     172        outptr[3] = ((inpts[2] & 0x7F) << 1) |
     173                    ((inpts[3] & 0x80) >> 7);
     174        outptr[4] = 0x01 | ((inpts[3] & 0x7F) << 1);
     175}
     176
     177static void directv_update_video_pes(unsigned char *ptr, int pos)
     178{
     179  //pos points at the 1st char after a pic start code
     180  int picture_coding_type;
     181  int hdr_len;
     182  unsigned int pts1, dts1;
     183  unsigned char *buf = ptr + pos;
     184  picture_coding_type = (buf[1] >> 3) & 0x07;
     185  hdr_len = (picture_coding_type > 1) ? 5 : 4;
     186  if(buf[hdr_len + 3] == 0xb5)
     187    hdr_len += 9;
     188  if(buf[hdr_len + 3] == 0xb2) {
     189    pts1 = ((buf[hdr_len+6] & 0x03)   << 30) +
     190           ((buf[hdr_len+7] & 0x7f) << 23) +
     191           ((buf[hdr_len+8])          << 15) +
     192           ((buf[hdr_len+9] & 0x7f) << 8) +
     193           buf[hdr_len+10];
     194    dts1 = ((buf[hdr_len+13] & 0x03)   << 30) +
     195           ((buf[hdr_len+14] & 0x7f) << 23) +
     196           ((buf[hdr_len+15])          << 15) +
     197           ((buf[hdr_len+16] & 0x7f) << 8) +
     198           buf[hdr_len+17];
     199    //NOTE:  This is wrong.  DSS timestamps only have a resolution of 2^32/300
     200    //printf("pts: %08x/%f dts: %08x/%f\n", pts1, pts1 / 27000000.0, dts1, dts1 / 27000000.0);
     201    ptr[7] |= 0xc0;
     202    directv_make_pespts(ptr+9, pts1/300);
     203    ptr[9] |= 0x30;
     204    directv_make_pespts(ptr+14, dts1/300);
     205    ptr[14] |= 0x10;
     206  }
     207}
     208
     209static void directv_fix_audio_pts(unsigned char *ptr)
     210{
     211  unsigned int pts = ((ptr[0] & 0x06) << 29) +
     212                     (ptr[1] << 22) +
     213                     ((ptr[2] & 0xfe) << 14) +
     214                     (ptr[3] << 7) +
     215                     (ptr[4] >> 1);
     216  directv_make_pespts(ptr, pts/300);
     217  ptr[0] |= 0x20;
     218}
     219
     220
     221static void directv_write_ts(r5kdev_t *r5kdev, unsigned char *ptr, int len, int pid, int start, int *cc)
     222{
     223  int stuff = 184 - len;
     224  //Note:  we know that there are 188 bytes allocated before 'ptr'
     225  //       that we can use for the header
     226  if(stuff > 0) {
     227    int stuff1 = stuff;
     228    while(stuff1 > 2) {
     229      *--ptr = 0xff;
     230      stuff1--;
     231    }
     232    if(stuff1 == 2) {
     233      *--ptr = 0x00;
     234    }
     235    *--ptr = stuff - 1;
     236    *--ptr = 0x30 | *cc;
     237  } else {
     238    *--ptr = 0x10 | *cc;
     239  }
     240  *--ptr = pid & 0xff;
     241  *--ptr = (start << 6) | (pid >> 8);
     242  *--ptr = 0x47;
     243  r5kdev->cb(ptr, 188, r5kdev->cb_data);
     244  *cc = (*cc+1) & 0x0f;
     245}
     246
     247static void directv_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len)
     248{
     249  int i;
     250  struct r5000_dtv *dtv = (struct r5000_dtv *)r5kdev->stbdata;
     251  for(i = 0; i < len; i+=2) {
     252    unsigned char data = buf[i];
     253    unsigned char type = buf[i+1];
     254    if(0xff == type) {
     255      //video
     256      dtv->video[dtv->vpos++] = data;
     257      if(dtv->vpos > 4 && dtv->video[dtv->vpos-2] == 0x01 &&
     258         dtv->video[dtv->vpos-3] == 0x00 && dtv->video[dtv->vpos-4] == 0x00) {
     259        if (data == 0xe0) {
     260          //HD video header (PES)
     261          directv_write_ts(r5kdev, dtv->video, dtv->vpos - 4, DTV_VPID, dtv->vstart, &dtv->video_cc);
     262          dtv->pat_pmt_count++;
     263          dtv->video[0] = 0x00;
     264          dtv->video[1] = 0x00;
     265          dtv->video[2] = 0x01;
     266          dtv->video[3] = 0xe0;
     267          dtv->vpos = 4;
     268          dtv->vstart = 1;
     269          dtv->vstate = data;
     270        } else if (data == 0xb3 || data == 0x00) {
     271          if (dtv->vstate == 0xff) {
     272            dtv->vstate = data;
     273            directv_write_ts(r5kdev, dtv->video, dtv->vpos - 4, DTV_VPID, dtv->vstart, &dtv->video_cc);
     274            dtv->pat_pmt_count++;
     275            //Create a PES header, but no PTS/DTS info yet so just use stuffing bytes
     276            dtv->vpos = directv_make_empty_pes(dtv->video, 0xe0);
     277            dtv->video[dtv->vpos++] = 0x00;
     278            dtv->video[dtv->vpos++] = 0x00;
     279            dtv->video[dtv->vpos++] = 0x01;
     280            dtv->video[dtv->vpos++] = data;
     281            dtv->vstart = 1;
     282            dtv->pic_pos = dtv->vpos;
     283          }
     284        }
     285      }
     286      if(dtv->vpos == 188) {
     287        if (dtv->vstate == 0x00)
     288          //We found pic frame without a PES header (SD)
     289          directv_update_video_pes(dtv->video, dtv->pic_pos);
     290        directv_write_ts(r5kdev, dtv->video, 184, DTV_VPID, dtv->vstart, &dtv->video_cc);
     291        dtv->pat_pmt_count++;
     292        dtv->video[0] = dtv->video[184];
     293        dtv->video[1] = dtv->video[185];
     294        dtv->video[2] = dtv->video[186];
     295        dtv->video[3] = dtv->video[187];
     296        dtv->vpos = 4;
     297        dtv->vstart = 0;
     298        dtv->vstate = 0xff;
     299      }
     300    } else if(0xfe == type) {
     301      //audio
     302      dtv->audio[dtv->apos++] = data;
     303      dtv->alen--;
     304      if(dtv->alen <= 0 && dtv->apos > 6 && dtv->audio[dtv->apos-3] == 0xbd && dtv->audio[dtv->apos-4] == 0x01 &&
     305         dtv->audio[dtv->apos-5] == 0x00 && dtv->audio[dtv->apos-6] == 0x00) {
     306        dtv->alen = (dtv->audio[dtv->apos-2] << 8) + data;
     307        directv_write_ts(r5kdev, dtv->audio, dtv->apos - 6, DTV_APID, dtv->astart, &dtv->audio_cc);
     308        dtv->pat_pmt_count++;
     309        dtv->audio[0] = 0x00;
     310        dtv->audio[1] = 0x00;
     311        dtv->audio[2] = 0x01;
     312        dtv->audio[3] = 0xbd;
     313        dtv->audio[4] = dtv->audio[dtv->apos-2];
     314        dtv->audio[5] = data;
     315        dtv->apos = 6;
     316        dtv->astart = 1;
     317        r5kdev->pmt[1].id = 0x81; //AC3
     318      } else if(dtv->alen <= 0 && dtv->apos > 6 && dtv->audio[dtv->apos-3] == 0xc0 && dtv->audio[dtv->apos-4] == 0x01 &&
     319           dtv->audio[dtv->apos-5] == 0x00 && dtv->audio[dtv->apos-6] == 0x00) {
     320        dtv->alen = (dtv->audio[dtv->apos-2] << 8) + data;
     321        directv_write_ts(r5kdev, dtv->audio, dtv->apos - 6, DTV_APID, dtv->astart, &dtv->audio_cc);
     322        dtv->pat_pmt_count++;
     323        dtv->audio[0] = 0x00;
     324        dtv->audio[1] = 0x00;
     325        dtv->audio[2] = 0x01;
     326        dtv->audio[3] = 0xc0;
     327        dtv->audio[4] = (dtv->alen + 3) >> 8;
     328        dtv->audio[5] = (dtv->alen + 3) & 0xff;
     329        dtv->audio[6] = 0x80;
     330        dtv->audio[7] = 0x80;
     331        dtv->audio[8] = 0x05;
     332        dtv->apos = 9;
     333        dtv->astart = 1;
     334        r5kdev->pmt[1].id = 0x04; //MP2
     335      } else if(dtv->apos == 190) {
     336        if(dtv->astart && dtv->audio[3] == 0xc0)
     337          directv_fix_audio_pts(dtv->audio+9);
     338        directv_write_ts(r5kdev, dtv->audio, 184, DTV_APID, dtv->astart, &dtv->audio_cc);
     339        dtv->pat_pmt_count++;
     340        dtv->audio[0] = dtv->audio[184];
     341        dtv->audio[1] = dtv->audio[185];
     342        dtv->audio[2] = dtv->audio[186];
     343        dtv->audio[3] = dtv->audio[187];
     344        dtv->audio[4] = dtv->audio[188];
     345        dtv->audio[5] = dtv->audio[189];
     346        dtv->apos = 6;
     347        dtv->astart = 0;
     348      }
     349    }
     350  }
     351  if(r5kdev->pmt[1].id && dtv->pat_pmt_count > DTV_PAT_PMT_COUNT) {
     352    r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
     353    r5000_send_pmt(r5kdev);
     354    dtv->pat_pmt_count = 0;
     355  }
     356}
     357
     358static void directv_start_stream(r5kdev_t *r5kdev)
     359{
     360  struct r5000_dtv *dtv = (struct r5000_dtv *)r5kdev->stbdata;
     361  dtv->vstart = 0;
     362  dtv->astart = 0;
     363  dtv->vpos = 0;
     364  dtv->apos = 0;
     365  dtv->video_cc = 0;
     366  dtv->audio_cc = 0;
     367  dtv->vstate = 0;
     368  dtv->pat_pmt_count = DTV_PAT_PMT_COUNT;
     369}
     370void directv_init(r5kdev_t *r5kdev)
     371{
     372  struct r5000_dtv *dtv = (struct r5000_dtv *)calloc(1, sizeof(struct r5000_dtv));
     373  dtv->video = dtv->vbuf + 188;
     374  dtv->audio = dtv->abuf + 188;
     375  dtv->pat_pmt_count = DTV_PAT_PMT_COUNT;
     376  dtv->vstate = 0xff;
     377  r5kdev->stbdata = dtv;
     378  r5kdev->pmt[0].id = 0x02; //MPEG2
     379  r5kdev->pmt[0].pid = DTV_VPID;
     380  r5kdev->pmt[1].id = 0x00;
     381  r5kdev->pmt[1].pid = DTV_APID;
     382  r5kdev->pmt[1].desc = r5000_pmt_audio_desc;
     383  r5kdev->num_pmt_entries = 2;
     384  r5kdev->process_block = directv_process_block;
     385  r5kdev->start_stream  = directv_start_stream;
     386  r5kdev->button = &directv_button_cmd;
     387  r5kdev->read_words = 1;
     388}
     389
     390void directv_free(r5kdev_t *r5kdev)
     391{
     392  free(r5kdev->stbdata);
     393}
  • new file libs/libmythtv/r5000/r5k_misc.c

    - +  
     1#include <stdio.h>
     2#include <string.h>
     3#include "r5000_internal.h"
     4
     5unsigned char r5000_pat_pkt[188] = {
     60x47, 0x40, 0x00, 0x13, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x06, 0xc5, 0x00, 0x00, 0x00, 0x01, 0xe0,
     70x21, 0x19, 0x3a, 0x82, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     80xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     90xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     100xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     110xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     120xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     130xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     140xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     150xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     160xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     170xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
     18
     19
     20struct r5k_descriptor r5000_pmt_audio_desc = {{0x06, 0x0a, 0x04, 0x65, 0x6e, 0x67, 0x00}};
     21struct r5k_descriptor r5000_pmt_video_desc = {{0x00}};
     22
     23//taken and adapted from libdtv, (c) Rolf Hakenes
     24// CRC32 lookup table for polynomial 0x04c11db7
     25static unsigned int crc_table[256] = {
     26   0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
     27   0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
     28   0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
     29   0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
     30   0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
     31   0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
     32   0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
     33   0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
     34   0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
     35   0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
     36   0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
     37   0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
     38   0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
     39   0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
     40   0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
     41   0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
     42   0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
     43   0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
     44   0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
     45   0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
     46   0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
     47   0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
     48   0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
     49   0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
     50   0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
     51   0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
     52   0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
     53   0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
     54   0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
     55   0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
     56   0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
     57   0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
     58   0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
     59   0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
     60   0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
     61   0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
     62   0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
     63   0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
     64   0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
     65   0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
     66   0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
     67   0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
     68   0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
     69
     70static void r5000_calc_crc(unsigned char *out, const unsigned char *d, int len)
     71{
     72   register int i;
     73   unsigned int crc = 0xFFFFFFFF;
     74   const unsigned char *u=(unsigned char*)d; // Saves '& 0xff'
     75
     76   for (i=0; i<len; i++)
     77      crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)];
     78
     79   *out++ = (crc >> 24) & 0xff;
     80   *out++ = (crc >> 16) & 0xff;
     81   *out++ = (crc >> 8) & 0xff;
     82   *out++ = (crc >> 0) & 0xff;
     83}
     84
     85static void r5000_build_pmt(r5kdev_t *r5kdev)
     86{
     87  int i;
     88  unsigned char *ptr;
     89  unsigned char ts[188] = {
     90  0x47, 0x40, 0x21, 0x10,
     91  0x00, 0x02,
     92  0xb0, 0x00,  //length
     93  0x00, 0x01,
     94  0xc3, 0x00, 0x00,
     95  0xf0, 0x00,  //PCR_PID
     96  0xf0, 0x00}; //Program Info Length
     97  ts[3] = 0x10 | r5kdev->pmt_next_cc;
     98  printf("Building PMT\n");
     99  ptr = ts + 17;
     100  for(i = 0; i < r5kdev->num_pmt_entries; i++) {
     101    *ptr++ = r5kdev->pmt[i].id;
     102    *ptr++ = 0xe0 | (r5kdev->pmt[i].pid>>8);
     103    *ptr++ = r5kdev->pmt[i].pid & 0xff;
     104    *ptr++ = 0xf0;
     105    if(IS_VIDEO(r5kdev->pmt[i].id)) {
     106      *ptr++ = 0x00;
     107      ts[13] = 0xe0 | (r5kdev->pmt[i].pid >> 8);
     108      ts[14] = r5kdev->pmt[i].pid & 0xff;
     109    } else {
     110      memcpy(ptr, r5kdev->pmt[i].desc.d, r5kdev->pmt[i].desc.d[0]+1);
     111      ptr += r5kdev->pmt[i].desc.d[0]+1;
     112    }
     113  }
     114  ts[7] = (ptr - ts) - 8/*header*/ + 4/*CRC*/;
     115  r5000_calc_crc(ptr, ts + 5, (ptr - ts) - 5);
     116  memset(ptr+4, 0xff, 188 - (ptr - ts - 4));
     117  memcpy(r5kdev->pmt_pkt, ts, 188);
     118}
     119
     120void r5000_send_pmt(r5kdev_t *r5kdev)
     121{
     122  if(r5kdev->pmt_pkt[0] != 0x47) {
     123    r5000_build_pmt(r5kdev);
     124  }
     125  r5kdev->pmt_pkt[3] = 0x10 | r5kdev->pmt_next_cc;
     126  r5kdev->pmt_next_cc = (r5kdev->pmt_next_cc + 1) & 0x0f;
     127  r5kdev->cb(r5kdev->pmt_pkt, 188, r5kdev->cb_data);
     128}
  • new file libs/libmythtv/r5000/r5k_sat.c

    - +  
     1//Support for Dish Network ViP211/ViP422 boxes
     2#include <stdio.h>
     3#include <string.h>
     4#include "r5000_internal.h"
     5
     6#define DTV_PAT_PMT_COUNT 5000
     7#define MAX_PKT_SIZE 272
     8#define MAX_PAT_SECTIONS 1
     9#define MAX_SIDS 200
     10#define MAX_EPIDS 5
     11
     12struct pat {
     13  int version;
     14  unsigned char last_section;
     15  unsigned char section_seen[MAX_PAT_SECTIONS];
     16  unsigned int pmts[MAX_SIDS];
     17  int pmt_count;
     18};
     19
     20struct sids {
     21  unsigned short sid;
     22  struct r5k_epid epid[MAX_EPIDS];
     23  unsigned char epid_count;
     24};
     25
     26struct r5000_sat {
     27  unsigned char buf[MAX_PKT_SIZE];
     28  unsigned int pos;
     29  int offset;
     30  unsigned char sync;
     31  unsigned char bytesize;
     32  unsigned char sync_byte;
     33  unsigned int has_sync_byte;
     34  unsigned int pat_pmt_count;
     35  unsigned int packet_size;
     36  unsigned int allowed_packet_size[8];
     37
     38  struct pat pats;
     39  struct sids *sids;
     40};
     41
     42static int sat_read_pat_pkt(unsigned char *pes, struct pat *pat, unsigned int size) {
     43  unsigned int sec, end;
     44  int version;
     45  unsigned char *ptr, last_sec;
     46
     47  if (pes[0] != 0x00) {
     48    printf(
     49             "read_pat: expected PAT table 0x00 but got 0x%02x\n", pes[0]);
     50    return 1;
     51  }
     52  end = (((pes[1] & 0x03) << 8 | pes[2]) + 3 - 4);
     53  if(end > size-4) {
     54    printf("read_pat: invalid PAT table size (%d > %d)\n", end, size-4);
     55    return 1;
     56  }
     57  version = (pes[5] >> 1) & 0x1f;
     58  sec = pes[6];
     59  last_sec = pes[7];
     60  if(last_sec >= MAX_PAT_SECTIONS) {
     61    printf("read_pat: illegal section count %d > %d\n",
     62             last_sec, MAX_PAT_SECTIONS);
     63    return 1;
     64  }
     65  if (pat->version != version || last_sec != pat->last_section) {
     66    pat->version = version;
     67    pat->last_section = last_sec;
     68    pat->pmt_count = 0;
     69  }
     70  if(pat->section_seen[sec])
     71    return 0;
     72  pat->section_seen[sec] = 1;
     73  for(ptr = pes + 8; ptr < pes + end; ptr += 4) {
     74    int sid, pid;
     75    struct filter *filt;
     76    sid = (ptr[0] << 8) | ptr[1];
     77    pid = ((ptr[2] & 0x1F) << 8) | ptr[3];
     78    if(sid != 0) {
     79      printf("found PID: %04x for sid: %d\n", pid, sid);
     80      pat->pmts[pat->pmt_count++] = (sid << 16) | pid;
     81    }
     82  }
     83  return 0;
     84}
     85
     86static int sat_read_pmt_pkt(unsigned char *buf, struct sids *sids,
     87                    unsigned int size) {
     88  //
     89  // NOTE we aren't using last_sec here yet!
     90  //
     91
     92  struct sids *sidptr = sids;
     93  unsigned int count, skip, pos;
     94  int sid, sec, last_sec, pcrpid, epid, type;
     95  if (buf[0] != 0x02) {
     96    printf("read_pmt expected table 0x02 but got 0x%02x\n", buf[0]);
     97    return -1;
     98  }
     99  count = (((buf[1] & 0x03) << 8) | buf[2]) + 3 - 4;
     100  sid = (buf[3] << 8) | buf[4];
     101  sec = buf[6];
     102  last_sec = buf[7];
     103  pcrpid = ((buf[8] & 0x1F) << 8) | buf[9];
     104  skip = ((buf[10] & 0x03) << 8) | buf[11];
     105  if(skip > count - 12 || count > size) {
     106    printf("skip: %d > count: %d - 12 || count > size: %d\n",
     107           skip, count, size);
     108    return -1;
     109  }
     110
     111  printf("read_pmt: sid: %d pcrpid: %d skip: %d count: %d\n", sid, pcrpid, skip, count);
     112  while(sidptr->sid != 0) {
     113    if(sidptr->sid == sid)
     114      break;
     115    sidptr++;
     116  }
     117  if(sidptr->sid != 0) {
     118    printf("Already seen sid: %d\n", sid);
     119    return -1;
     120  }
     121  sidptr->sid = sid;
     122  sidptr->epid_count = 0;
     123  for(pos = 12 + skip; pos < count;) {
     124    int j;
     125    struct r5k_epid *pidptr = &sidptr->epid[sidptr->epid_count];
     126    type = buf[pos];
     127    epid = ((buf[pos+1] & 0x1F) << 8) | buf[pos+2];
     128    skip = ((buf[pos+3] & 0x03) << 8) | buf[pos+4];
     129    pidptr->pid = epid;
     130    pidptr->id  = type;
     131    memcpy(pidptr->desc.d, buf + 4, skip + 1);
     132    sidptr->epid_count++;
     133    printf("read_pmt: epid %04x (type %02x) mapped to sid %d\n", epid, type, sid);
     134    pos += 5 + skip;
     135  }
     136  ++sidptr;
     137  sidptr->sid = 0;
     138  return 0;
     139}
     140void sat_add_pmt(r5kdev_t *r5kdev, struct r5k_epid *epid)
     141{
     142  int i;
     143  int is_video = IS_VIDEO(epid->id);
     144
     145  for(i = 0; i < r5kdev->num_pmt_entries; i++) {
     146    if(r5kdev->pmt[i].pid == epid->pid) {
     147      if(r5kdev->pmt[i].id == epid->id)
     148        return;
     149      //different table_id for existing pid.  Reset
     150      r5kdev->num_pmt_entries = 0;
     151      r5kdev->pmt_state = 0;
     152      r5kdev->pmt_pkt[0] = 0;
     153      break;
     154    }
     155    if(is_video) {
     156      if(IS_VIDEO(r5kdev->pmt[i].id)) {
     157        //a video entry already exists.  Reset
     158        r5kdev->num_pmt_entries = 0;
     159        r5kdev->pmt_state = 0;
     160        r5kdev->pmt_pkt[0] = 0;
     161        break;
     162      }
     163    }
     164  }
     165  //Didn't find this PID, add it
     166  if(i == R5K_MAX_PIDS)
     167    return;
     168  printf("Adding %04x: %02x @ %08x\n", epid->pid, epid->id, r5kdev->bytes_read);
     169  r5kdev->pmt[r5kdev->num_pmt_entries++] = *epid;
     170  r5kdev->pmt_state |= is_video ? 0x01 : 0x02;
     171}
     172
     173void sat_process_ts(r5kdev_t *r5kdev, unsigned char *buf)
     174{
     175  struct r5000_sat *sat = (struct r5000_sat *)r5kdev->stbdata;
     176  int stream_id, pid, afc, af_size = 0;
     177  int i, j, k;
     178  pid = ((buf[1] << 8) | buf[2]) & 0x1fff;
     179  if(pid == 0x1fff)
     180    return;
     181  if(! sat->pats.pmt_count) {
     182    if(pid != 0 || !buf[1] & 0x40)
     183      return;
     184    sat_read_pat_pkt(buf+buf[4]+5, &sat->pats, 188-buf[4]-5);
     185    if(sat->pats.pmt_count)
     186      sat->sids = calloc(1, sizeof(struct sids)*(sat->pats.pmt_count+1));
     187  } else {
     188    if(! r5kdev->num_pmt_entries) {
     189      for(i = 0; i < sat->pats.pmt_count; i++) {
     190        if(pid == (unsigned short)(sat->pats.pmts[i])) {
     191          if(buf[1] & 0x40 && buf[4]+5 < 188 && buf[buf[4]+5] == 0x02) {
     192            sat_read_pmt_pkt(buf+buf[4]+5, sat->sids, 188-buf[4]-5);
     193          }
     194          break;
     195        }
     196        for(j = 0; j < sat->sids[i].epid_count; j++) {
     197          if(pid == sat->sids[i].epid[j].pid) {
     198            if(sat->sids[i].epid[j].id == 0x80 ||
     199               IS_VIDEO(sat->sids[i].epid[j].id)) {
     200              if(! r5kdev->channel)
     201                r5kdev->channel = sat->sids[i].sid;
     202              if(r5kdev->channel == sat->sids[i].sid) {
     203                //Found unencrypted video.  Choose this one
     204                // Assume this is MPEG2.  Don't know what MPEG4 looks like yet
     205                sat_add_pmt(r5kdev, &sat->sids[i].epid[j]);
     206                for(k = 0; k < sat->sids[i].epid_count; k++) {
     207                  if(sat->sids[i].epid[k].id == 0x81 ||
     208                     sat->sids[i].epid[k].id == 0xbd) {
     209                    sat_add_pmt(r5kdev, &sat->sids[i].epid[k]);
     210                  }
     211                }
     212                r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
     213                r5000_send_pmt(r5kdev);
     214                sat->pat_pmt_count = 0;
     215              }
     216            }
     217          }
     218        }
     219      }
     220    } else {
     221printf("PID: %04x\n", pid);
     222      for(i = 0; i < r5kdev->num_pmt_entries; i++) {
     223        if(pid == r5kdev->pmt[i].pid) {
     224          r5kdev->cb(sat->buf, 188, r5kdev->cb_data);
     225          sat->pat_pmt_count++;
     226          break;
     227        }
     228      }
     229    }
     230  }
     231}
     232
     233static void sat_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len)
     234{
     235  struct r5000_sat *sat = (struct r5000_sat *)r5kdev->stbdata;
     236
     237  int pos;
     238  int sync = 1;
     239  if(! r5kdev->streaming)
     240    return;
     241  if(len <= 0)
     242    return;
     243
     244  for(pos = sat->offset; pos < len; pos += sat->bytesize) {
     245    if(! sat->sync) {
     246      if(buf[pos] == 0x47) {
     247        int i;
     248        if(pos == 0x1344)
     249          printf("here\n");
     250        if (pos + (sat->allowed_packet_size[0]<<1) < len) {
     251          if((buf[pos+1] & 0xfc) == 0xfc && (buf[pos+3] & 0xfc) == 0xfc &&
     252             (buf[pos+5] & 0xfc) == 0xfc && (buf[pos+7] & 0xfc) == 0xfc) {
     253             sat->bytesize = 2;
     254          }
     255          for(i=0; sat->allowed_packet_size[i] != 0; i++) {
     256            if(buf[pos+(sat->allowed_packet_size[i] * sat->bytesize)] == 0x47) {
     257              printf("(%d) Found %d byte sync at %08x: bytesize = %d\n",
     258                    r5kdev->nexturb, sat->allowed_packet_size[i],
     259                    r5kdev->bytes_read+pos, sat->bytesize);
     260              sat->packet_size = sat->allowed_packet_size[i];
     261              sat->sync = 1;
     262              sat->buf[0] = 0x47;
     263              sat->pos = 1;
     264              break;
     265            }
     266          }
     267        }
     268      }
     269      continue;
     270    }
     271    if (sat->pos == 0 && buf[pos] != 0x47) {
     272      sat->sync = 0;
     273      sat->bytesize = 1;
     274      printf("(%d)Lost sync at %08x\n", r5kdev->nexturb,
     275             r5kdev->bytes_read+pos);
     276      continue;
     277    }
     278    if(sat->pos == 3 && (buf[pos] & 0xc0) != 0x00) {
     279      // Encrypted channel, skip this packet
     280      sat->pos = 0;
     281      pos += sat->bytesize * (sat->packet_size - 4); //Loop adds additional 2
     282      continue;
     283    }
     284    sat->buf[sat->pos++] = buf[pos];
     285    if (sat->pos == sat->packet_size) {
     286      sat_process_ts(r5kdev, sat->buf);
     287      //if packet size > 188, assume remaining bytes are parity and ignore
     288      sat->pos = 0;
     289    }
     290  }
     291  sat->offset = pos - len;
     292  if(1 && r5kdev->pmt_state == 0x03 && sat->pat_pmt_count > DTV_PAT_PMT_COUNT) {
     293    r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data);
     294    r5000_send_pmt(r5kdev);
     295    sat->pat_pmt_count = 0;
     296  }
     297}
     298
     299static void sat_start_stream(r5kdev_t *r5kdev)
     300{
     301  struct r5000_sat *sat = (struct r5000_sat *)r5kdev->stbdata;
     302  sat->offset = 0;
     303  sat->sync = 0;
     304  sat->pos = 0;
     305  sat->bytesize = 1;
     306}
     307
     308void sat_init(r5kdev_t *r5kdev, r5ktype_t type)
     309{
     310  struct r5000_sat *sat =
     311                   (struct r5000_sat *)calloc(1, sizeof(struct r5000_sat));
     312  r5kdev->stbdata = sat;
     313  sat->pat_pmt_count = DTV_PAT_PMT_COUNT;
     314  if(type == R5K_STB_HDD) {
     315    sat->sync_byte = 0xff;
     316    sat->has_sync_byte = 1;
     317    sat->allowed_packet_size[0] = 272;
     318    sat->allowed_packet_size[1] = 233;
     319    sat->allowed_packet_size[2] = 204;
     320    sat->allowed_packet_size[3] = 188;
     321    sat->allowed_packet_size[4] = 0;
     322  } else {
     323    sat->allowed_packet_size[0] = 188;
     324    sat->allowed_packet_size[1] = 0;
     325  }
     326  r5kdev->process_block = sat_process_block;
     327  r5kdev->start_stream  = sat_start_stream;
     328}
     329
     330void sat_free(r5kdev_t *r5kdev)
     331{
     332  free(r5kdev->stbdata);
     333}
     334
  • new file libs/libmythtv/r5000/r5000init.h

    - +  
     1#ifndef R5000_INIT_H
     2#define R5000_INIT_H
     3
     4#define R5K_INIT_MAX 9
     5#define R5K_INIT_SERIAL 8
     6#define R5K_DEFAULT_SLEEP 100000
     7struct {
     8  int rsleep;
     9  int rlen;
     10  int wsleep;
     11  int wlen;
     12  unsigned char data[0x40];
     13} r5kinit[R5K_INIT_MAX] = {
     14// 0
     15{R5K_DEFAULT_SLEEP, -1, 0, 64,
     16    {0x30}},
     17// 1
     18{R5K_DEFAULT_SLEEP, 1, 0, 64,
     19    {0x08, 0x00, 0x20, 0x00, 0x00, 0x3a, 0xd4, 0x29, 0x7c, 0x56, 0x31, 0x44, 0x86, 0x6d, 0x0d, 0x0d,
     20     0x1b, 0x0a, 0xad, 0x0f, 0xd0, 0x2e, 0x94, 0x3f, 0xd4, 0x08, 0xa2, 0x4b, 0x68, 0x14, 0x1f, 0x13,
     21     0x04, 0x62, 0x1b, 0x14, 0xb9, 0x69, 0xcc, 0x25, 0x91, 0x06, 0xc9, 0x26, 0xf9, 0x41, 0x64, 0x46,
     22     0x7d, 0x17, 0x61, 0x09, 0x5c, 0x5b, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
     23// 2
     24{R5K_DEFAULT_SLEEP, 1, 0, 64,
     25    {0x08, 0x00, 0x5a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     26     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     27     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     28     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
     29// 3
     30{R5K_DEFAULT_SLEEP, 1, 0, 64,
     31    {0x08, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     32     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     33     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     34     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
     35// 4
     36{R5K_DEFAULT_SLEEP, 1, R5K_DEFAULT_SLEEP, 64,
     37    {0x08, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     38     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     39     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     40     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
     41// 5
     42{R5K_DEFAULT_SLEEP, 26, 0, 6,
     43    {0x08, 0x01, 0x00, 0x00, 0x01, 0x14}},
     44// 6
     45{R5K_DEFAULT_SLEEP, 1, 0, 64,
     46    {0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     47     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     48     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     49     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
     50// 7
     51{R5K_DEFAULT_SLEEP, 22, 0, 64,
     52    {0x08, 0x01, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     53     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     54     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     55     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
     56// 8
     57{R5K_DEFAULT_SLEEP, 4, 0, 1,
     58    {0x20}}
     59};
     60
     61#endif