Ticket #4752: r5000_r7.patch
File r5000_r7.patch, 124.0 KB (added by , 16 years ago) |
---|
-
configure
old new 158 158 echo " --disable-v4l disable Video4Linux support" 159 159 echo " --disable-ivtv disable ivtv support (PVR-x50) req. v4l support" 160 160 echo " --disable-dvb disable DVB support" 161 echo " --disable-r5000 disable support for R5000 USB STBs" 161 162 echo " --dvb-path=HDRLOC location of directory containing" 162 163 echo " 'linux/dvb/frontend.h', not the" 163 164 echo " directory with frontend.h [$dvb_path]" … … 888 889 hdhomerun 889 890 iptv 890 891 ivtv 892 r5000 891 893 joystick_menu 892 894 libfftw3 893 895 lirc … … 1042 1044 dbox2_deps="backend" 1043 1045 dvb_deps="backend" 1044 1046 firewire_deps="backend" 1047 r5000_deps="backend" 1045 1048 iptv_deps="backend" 1046 1049 ivtv_deps="backend v4l" 1047 1050 hdhomerun_deps="backend" … … 1175 1178 hdhomerun="yes" 1176 1179 iptv="yes" 1177 1180 ivtv="yes" 1181 r5000="yes" 1178 1182 joystick_menu="default" 1179 1183 lamemp3="yes" 1180 1184 lirc="yes" … … 2972 2976 echo "DBox2 support ${dbox2-no}" 2973 2977 echo "HDHomeRun support ${hdhomerun-no}" 2974 2978 echo "IPTV support ${iptv-no}" 2979 echo "R5000 support ${r5000-no}" 2975 2980 fi 2976 2981 2977 2982 if enabled frontend; then -
libs/libmythtv/cardutil.h
old new 53 53 FIREWIRE, 54 54 HDHOMERUN, 55 55 FREEBOX, 56 R5000, 56 57 }; 57 58 58 59 static enum CARD_TYPES toCardType(const QString &name) … … 81 82 return HDHOMERUN; 82 83 if ("FREEBOX" == name) 83 84 return FREEBOX; 85 if ("R5000" == name) 86 return R5000; 84 87 return ERROR_UNKNOWN; 85 88 } 86 89 … … 89 92 return 90 93 (rawtype != "DVB") && 91 94 (rawtype != "FIREWIRE") && (rawtype != "DBOX2") && 92 (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX"); 95 (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX") && 96 (rawtype != "R5000"); 93 97 } 94 98 95 99 static bool IsUnscanable(const QString &rawtype) 96 100 { 97 101 return 98 (rawtype == "FIREWIRE") || (rawtype == "DBOX2"); 102 (rawtype == "FIREWIRE") || (rawtype == "DBOX2") || 103 (rawtype == "R5000"); 99 104 } 100 105 101 106 static bool IsEITCapable(const QString &rawtype) -
libs/libmythtv/libmythtv.pro
old new 491 491 DEFINES += USING_DVB 492 492 } 493 493 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 494 511 DEFINES += USING_BACKEND 495 512 } 496 513 -
libs/libmythtv/signalmonitor.h
old new 297 297 (cardtype.upper() == "HDTV") || 298 298 (cardtype.upper() == "HDHOMERUN") || 299 299 (cardtype.upper() == "FIREWIRE") || 300 (cardtype.upper() == "FREEBOX")); 300 (cardtype.upper() == "FREEBOX") || 301 (cardtype.upper() == "R5000")); 301 302 } 302 303 303 304 inline bool SignalMonitor::IsSupported(const QString &cardtype) -
libs/libmythtv/signalmonitor.cpp
old new 41 41 # include "firewirechannel.h" 42 42 #endif 43 43 44 #ifdef USING_R5000 45 # include "r5000signalmonitor.h" 46 # include "r5000channel.h" 47 #endif 48 44 49 #undef DBG_SM 45 50 #define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \ 46 51 "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG); … … 127 132 signalMonitor = new FirewireSignalMonitor(db_cardnum, fc); 128 133 } 129 134 #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 130 143 131 144 if (!signalMonitor) 132 145 { -
libs/libmythtv/cardutil.cpp
old new 1457 1457 if (("FIREWIRE" == cardtype) || 1458 1458 ("FREEBOX" == cardtype) || 1459 1459 ("DBOX2" == cardtype) || 1460 ("HDHOMERUN" == cardtype)) 1460 ("HDHOMERUN" == cardtype) || 1461 ("R5000" == cardtype)) 1461 1462 { 1462 1463 ret += "MPEG2TS"; 1463 1464 } … … 1582 1583 if (("FIREWIRE" == cardtype) || 1583 1584 ("FREEBOX" == cardtype) || 1584 1585 ("DBOX2" == cardtype) || 1585 ("HDHOMERUN" == cardtype)) 1586 ("HDHOMERUN" == cardtype) || 1587 ("R5000" == cardtype)) 1586 1588 { 1587 1589 inputs += "MPEG2TS"; 1588 1590 } -
libs/libmythtv/videosource.cpp
old new 36 36 #include "frequencies.h" 37 37 #include "diseqcsettings.h" 38 38 #include "firewiredevice.h" 39 #include "r5000device.h" 39 40 #include "compat.h" 40 41 41 42 … … 1297 1298 } 1298 1299 }; 1299 1300 1301 class 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 1319 class 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 }; 1336 class 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 1300 1353 class IPTVHost : public LineEditSetting, public CaptureCardDBStorage 1301 1354 { 1302 1355 public: … … 1481 1534 #ifdef USING_IPTV 1482 1535 addTarget("FREEBOX", new IPTVConfigurationGroup(parent)); 1483 1536 #endif // USING_IPTV 1537 1538 #ifdef USING_R5000 1539 addTarget("R5000", new R5000ConfigurationGroup(parent)); 1540 #endif // USING_R5000 1484 1541 } 1485 1542 1486 1543 void CaptureCardGroup::triggerChanged(const QString& value) … … 1668 1725 #ifdef USING_IPTV 1669 1726 setting->addSelection(QObject::tr("Network Recorder"), "FREEBOX"); 1670 1727 #endif // USING_IPTV 1728 1729 #ifdef USING_R5000 1730 setting->addSelection(QObject::tr("R5000 Capable STB"), "R5000"); 1731 #endif // USING_R5000 1671 1732 } 1672 1733 1673 1734 class CardID : public SelectLabelSetting, public CardInputDBStorage -
libs/libmythtv/tv_rec.cpp
old new 50 50 #include "hdhrchannel.h" 51 51 #include "iptvchannel.h" 52 52 #include "firewirechannel.h" 53 #include "r5000channel.h" 53 54 54 55 #include "recorderbase.h" 55 56 #include "NuppelVideoRecorder.h" … … 59 60 #include "hdhrrecorder.h" 60 61 #include "iptvrecorder.h" 61 62 #include "firewirerecorder.h" 63 #include "r5000recorder.h" 62 64 63 65 #ifdef USING_V4L 64 66 #include "channel.h" … … 199 201 init_run = true; 200 202 #endif 201 203 } 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 } 202 214 else // "V4L" or "MPEG", ie, analog TV 203 215 { 204 216 #ifdef USING_V4L … … 1017 1029 recorder->SetOption("mrl", genOpt.videodev); 1018 1030 #endif // USING_IPTV 1019 1031 } 1032 else if (genOpt.cardtype == "R5000") 1033 { 1034 #ifdef USING_R5000 1035 recorder = new R5000Recorder(this, GetR5000Channel()); 1036 #endif // USING_R5000 1037 } 1020 1038 else 1021 1039 { 1022 1040 #ifdef USING_V4L … … 1230 1248 #endif // USING_FIREWIRE 1231 1249 } 1232 1250 1251 R5000Channel *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 1233 1260 Channel *TVRec::GetV4LChannel(void) 1234 1261 { 1235 1262 #ifdef USING_V4L -
libs/libmythtv/transporteditor.cpp
old new 735 735 left->addChild(new Modulation(id, nType)); 736 736 } 737 737 else if ((CardUtil::FIREWIRE == nType) || 738 (CardUtil::FREEBOX == nType)) 738 (CardUtil::FREEBOX == nType) || 739 (CardUtil::R5000 == nType)) 739 740 { 740 741 left->addChild(new DTVStandard(id, true, true)); 741 742 } -
libs/libmythtv/tv_rec.h
old new 39 39 class FirewireChannel; 40 40 class Channel; 41 41 class HDHRChannel; 42 class R5000Channel; 42 43 43 44 class MPEGStreamData; 44 45 class ProgramMapTable; … … 281 282 HDHRChannel *GetHDHRChannel(void); 282 283 DVBChannel *GetDVBChannel(void); 283 284 FirewireChannel *GetFirewireChannel(void); 285 R5000Channel *GetR5000Channel(void); 284 286 Channel *GetV4LChannel(void); 285 287 286 288 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 16 R5000Channel::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 29 bool 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 84 bool 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 105 void R5000Channel::Close(void) 106 { 107 VERBOSE(VB_CHANNEL, LOC + "Close()"); 108 if (isopen) 109 { 110 device->ClosePort(); 111 isopen = false; 112 } 113 } 114 115 QString R5000Channel::GetDevice(void) const 116 { 117 return videodevice; 118 } 119 120 bool 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 133 R5000Device::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 146 bool 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 164 bool 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 20 QMap<uint64_t,QString> R5000Device::s_id_to_model; 21 QMutex R5000Device::s_static_lock; 22 23 unsigned 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 34 class 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 }; 61 QMutex R5kPriv::s_lock; 62 63 //callback functions 64 void *r5000_device_port_handler_thunk(void *param); 65 66 R5000Device::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 76 R5000Device::~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 92 void 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 110 void 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 129 bool 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 153 bool 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 169 bool 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 179 R5000Device::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 190 bool 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 203 void 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 217 void 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 226 void 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 247 QString 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 262 bool R5000Device::IsSTBSupported(const QString &panel_model) 263 { 264 return true; 265 } 266 267 bool 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 309 bool 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 347 void *r5000_device_port_handler_thunk(void *param) 348 { 349 R5000Device *mon = (R5000Device*) param; 350 mon->RunPortHandler(); 351 return NULL; 352 } 353 354 void 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 378 QStringList 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 392 int 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 18 R5000Recorder::R5000Recorder(TVRec *rec, R5000Channel *chan) : 19 DTVRecorder(rec), _mpeg_stream_data(NULL), 20 channel(chan), isopen(false) 21 { 22 } 23 24 R5000Recorder::~R5000Recorder() 25 { 26 SetStreamData(NULL); 27 Close(); 28 } 29 30 bool R5000Recorder::Open(void) 31 { 32 if (!isopen) 33 isopen = channel->GetR5000Device()->OpenPort(); 34 35 return isopen; 36 } 37 38 void R5000Recorder::Close(void) 39 { 40 if (isopen) 41 { 42 channel->GetR5000Device()->ClosePort(); 43 isopen = false; 44 } 45 } 46 47 void R5000Recorder::StartStreaming(void) 48 { 49 channel->GetR5000Device()->AddListener(this); 50 } 51 52 void R5000Recorder::StopStreaming(void) 53 { 54 channel->GetR5000Device()->RemoveListener(this); 55 } 56 57 void 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 84 void 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 126 void 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 158 void 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 170 bool 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 194 void 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 218 void 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 229 void 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 21 const uint R5000SignalMonitor::kPowerTimeout = 3000; /* ms */ 22 const uint R5000SignalMonitor::kBufferTimeout = 5000; /* ms */ 23 24 QMap<void*,uint> R5000SignalMonitor::pat_keys; 25 QMutex 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 */ 42 R5000SignalMonitor::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 */ 65 R5000SignalMonitor::~R5000SignalMonitor() 66 { 67 VERBOSE(VB_CHANNEL, LOC + "dtor"); 68 Stop(); 69 } 70 71 void 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 */ 81 void 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 93 void 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 117 void 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 133 void *R5000SignalMonitor::TableMonitorThread(void *param) 134 { 135 R5000SignalMonitor *mon = (R5000SignalMonitor*) param; 136 mon->RunTableMonitor(); 137 return NULL; 138 } 139 140 void 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 174 void 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 */ 193 void 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 */ 304 void 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 15 class 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> 12 using namespace std; 13 14 // Qt headers 15 #include <qstring.h> 16 #include <qmutex.h> 17 18 // MythTV headers 19 #include "streamlisteners.h" 20 21 extern "C" { 22 #include "r5000/r5000.h" 23 } 24 25 class TSPacket; 26 class R5kPriv; 27 class 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; 105 private: 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 15 class TVRec; 16 class 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 */ 24 class 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 14 class R5000Channel; 15 16 class 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. 23 extern int usb_debug; 24 25 struct 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. 40 typedef enum { 41 USB_ERROR_TYPE_NONE = 0, 42 USB_ERROR_TYPE_STRING, 43 USB_ERROR_TYPE_ERRNO, 44 } usb_error_type_t; 45 46 extern char usb_error_str[1024]; 47 extern 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 57 static int urb_signr = 0; 58 void (*urb_completion_callback)(struct usbdevfs_urb *) = NULL; 59 #define USB_ASYNC_COMPLETION_SIGNAL (SIGRTMIN + 5) 60 61 void 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 88 int 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 101 struct 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 136 int 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 227 int 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 249 int 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 294 int 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. 7 struct usb_iso_packet_desc { 8 unsigned int length; 9 unsigned int actual_length; 10 unsigned int status; 11 }; 12 #endif 13 14 int usbdevfs_urb_signal_completion(void (*cb)( struct usbdevfs_urb *)); 15 struct usbdevfs_urb *usb_bulk_setup(struct usbdevfs_urb *iso_urb, unsigned char ep, 16 char *bytes, int size); 17 int usb_isochronous_setup(struct usbdevfs_urb **iso_urb, unsigned char ep, 18 int pktsize, char *bytes, int size); 19 int usb_urb_submit(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb, 20 struct timeval *tv_rsubmit); 21 int usb_urb_reap(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb, 22 int timeout_usec); 23 int 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 9 char strmfile[256] = "/tmp/strm"; 10 int fd = -1; 11 #endif 12 13 #ifdef R5K_RAWUSB 14 int 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 26 static int r5000_usb_init = 0; 27 enum { 28 R5K_PMT_START = 0x01, 29 R5K_PMT_READY = 0x02 30 }; 31 32 int 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 44 int r5000_free_urbs(r5kdev_t *r5kdev) 45 { 46 free(r5kdev->urbs); 47 free(r5kdev->buffer); 48 return 0; 49 } 50 51 usb_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 87 int 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 131 int 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 159 int 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 173 r5kdev_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 241 int 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 270 int 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 301 int r5000_read_status(r5kdev_t *r5kdev, unsigned char *buf) 302 { 303 return usb_bulk_read(r5kdev->handle, 129, buf, 128, 5000); 304 } 305 306 int 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 324 int 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 348 int 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 388 int 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 9 typedef struct { 10 unsigned char serial[R5K_MAX_DEVS][8]; 11 int count; 12 } r5kenum_t; 13 14 typedef 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 22 extern r5kdev_t *r5000_open(r5ktype_t type, unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, const char *serial); 23 extern int r5000_close(r5kdev_t *r5kdev); 24 extern int r5000_start_stream(r5kdev_t *r5kdev); 25 extern int r5000_stop_stream(r5kdev_t *r5kdev); 26 extern int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec); 27 extern int r5000_get_power_state(r5kdev_t *r5kdev); 28 extern int r5000_toggle_on_off(r5kdev_t *r5kdev); 29 extern int r5000_change_channel(r5kdev_t *r5kdev, int chan); 30 extern 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 21 struct r5k_descriptor { 22 unsigned char d[10]; 23 }; 24 25 struct r5k_epid { 26 int pid; 27 unsigned char id; 28 struct r5k_descriptor desc; 29 }; 30 31 struct 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 49 struct 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 76 extern unsigned char r5000_pat_pkt[188]; 77 extern struct r5k_descriptor r5000_pmt_audio_desc; 78 extern struct r5k_descriptor r5000_pmt_video_desc; 79 extern void r5000_send_pmt(r5kdev_t *r5kdev); 80 81 //Support for all DirecTV boxes 82 extern void directv_init(r5kdev_t *r5kdev); 83 extern void directv_free(r5kdev_t *r5kdev); 84 85 //Support for ViP series Dish Network boxes 86 extern void vip_init(r5kdev_t *r5kdev); 87 extern void vip_free(r5kdev_t *r5kdev); 88 89 //Support for HDD and DSR series satellite/cable boxes 90 extern void sat_init(r5kdev_t *r5kdev, r5ktype_t type); 91 extern 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 6 struct r5000_vip { 7 unsigned char leftover[188]; 8 int offset; 9 }; 10 11 struct r5000_buttons vip_button_cmd = 12 { 13 0x40, //len 14 400000, //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 108 void 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 144 void 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 199 static 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 247 static void vip_start_stream(r5kdev_t *r5kdev) 248 { 249 struct r5000_vip *vip = (struct r5000_vip *)r5kdev->stbdata; 250 vip->offset = 0; 251 } 252 253 void 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 262 void 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 11 struct 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 28 struct r5000_buttons directv_button_cmd = 29 { 30 0x49, //len 31 400000, //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 138 static 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 162 static 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 177 static 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 209 static 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 221 static 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 247 static 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 358 static 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 } 370 void 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 390 void 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 5 unsigned char r5000_pat_pkt[188] = { 6 0x47, 0x40, 0x00, 0x13, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x06, 0xc5, 0x00, 0x00, 0x00, 0x01, 0xe0, 7 0x21, 0x19, 0x3a, 0x82, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 8 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 9 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 10 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 11 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 12 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 13 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 14 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 15 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 16 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 17 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 18 19 20 struct r5k_descriptor r5000_pmt_audio_desc = {{0x06, 0x0a, 0x04, 0x65, 0x6e, 0x67, 0x00}}; 21 struct r5k_descriptor r5000_pmt_video_desc = {{0x00}}; 22 23 //taken and adapted from libdtv, (c) Rolf Hakenes 24 // CRC32 lookup table for polynomial 0x04c11db7 25 static 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 70 static 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 85 static 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 120 void 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 12 struct 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 20 struct sids { 21 unsigned short sid; 22 struct r5k_epid epid[MAX_EPIDS]; 23 unsigned char epid_count; 24 }; 25 26 struct 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 42 static 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 86 static 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 } 140 void 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 173 void 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 { 221 printf("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 233 static 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 299 static 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 308 void 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 330 void 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 7 struct { 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