Ticket #4752: r5000_r7.patch

File r5000_r7.patch, 124.0 KB (added by alannisota@…, 4 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