Ticket #4752: r5000_r2.patch
File r5000_r2.patch, 89.6 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]" … … 870 871 hdhomerun 871 872 iptv 872 873 ivtv 874 r5000 873 875 joystick_menu 874 876 lirc 875 877 opengl_vsync … … 1022 1024 dbox2_deps="backend" 1023 1025 dvb_deps="backend" 1024 1026 firewire_deps="backend" 1027 r5000_deps="backend" 1025 1028 iptv_deps="backend" 1026 1029 ivtv_deps="backend v4l" 1027 1030 hdhomerun_deps="backend" … … 1153 1156 hdhomerun="yes" 1154 1157 iptv="yes" 1155 1158 ivtv="yes" 1159 r5000="yes" 1156 1160 joystick_menu="default" 1157 1161 lamemp3="yes" 1158 1162 lirc="yes" … … 2928 2932 echo "DBox2 support ${dbox2-no}" 2929 2933 echo "HDHomeRun support ${hdhomerun-no}" 2930 2934 echo "IPTV support ${iptv-no}" 2935 echo "R5000 support ${r5000-no}" 2931 2936 fi 2932 2937 2933 2938 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 489 489 DEFINES += USING_DVB 490 490 } 491 491 492 #Support for R5000 usb device 493 using_r5000 { 494 HEADERS += r5000channel.h r5000recorder.h 495 HEADERS += r5000signalmonitor.h r5000device.h 496 HEADERS += r5000/r5000.h r5000/libusb_augment.h 497 498 SOURCES += r5000channel.cpp r5000recorder.cpp 499 SOURCES += r5000signalmonitor.cpp r5000device.cpp 500 SOURCES += r5000/r5000.c r5000/libusb_augment.c 501 502 LIBS += -lusb 503 DEFINES += USING_R5000 504 } 505 492 506 DEFINES += USING_BACKEND 493 507 } 494 508 -
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 R5000ConfigurationGroup : public VerticalConfigurationGroup 1320 { 1321 public: 1322 R5000ConfigurationGroup(CaptureCard& a_parent): 1323 VerticalConfigurationGroup(false, true, false, false), 1324 parent(a_parent) 1325 { 1326 setUseLabel(false); 1327 addChild(new R5000Serial(parent)); 1328 addChild(new SignalTimeout(parent, 2000, 1000)); 1329 addChild(new ChannelTimeout(parent, 9000, 1750)); 1330 addChild(new SingleCardInput(parent)); 1331 }; 1332 1333 private: 1334 CaptureCard &parent; 1335 }; 1336 1300 1337 class IPTVHost : public LineEditSetting, public CaptureCardDBStorage 1301 1338 { 1302 1339 public: … … 1481 1518 #ifdef USING_IPTV 1482 1519 addTarget("FREEBOX", new IPTVConfigurationGroup(parent)); 1483 1520 #endif // USING_IPTV 1521 1522 #ifdef USING_R5000 1523 addTarget("R5000", new R5000ConfigurationGroup(parent)); 1524 #endif // USING_R5000 1484 1525 } 1485 1526 1486 1527 void CaptureCardGroup::triggerChanged(const QString& value) … … 1668 1709 #ifdef USING_IPTV 1669 1710 setting->addSelection(QObject::tr("Network Recorder"), "FREEBOX"); 1670 1711 #endif // USING_IPTV 1712 1713 #ifdef USING_R5000 1714 setting->addSelection(QObject::tr("R5000 Capable STB"), "R5000"); 1715 #endif // USING_R5000 1671 1716 } 1672 1717 1673 1718 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); 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 FireWireDBOptions &firewire_opts) : 17 DTVChannel(parent), 18 videodevice(_videodevice), 19 fw_opts(firewire_opts), 20 device(NULL), 21 current_channel(0), 22 isopen(false) 23 { 24 device = new R5000Device(videodevice, 0, fw_opts.speed); 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(QString serial, uint subunitid, uint speed) : 67 m_serial(serial), m_subunitid(subunitid), 68 m_speed(speed), 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 r5000_change_channel(usbdev, channel); 199 return true; 200 } 201 202 void R5000Device::BroadcastToListeners( 203 const unsigned char *data, uint dataSize) 204 { 205 if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) && 206 ((data[1] & 0x1f) == 0) && (data[2] == 0)) 207 { 208 ProcessPATPacket(*((const TSPacket*)data)); 209 } 210 211 vector<TSDataListener*>::iterator it = m_listeners.begin(); 212 for (; it != m_listeners.end(); ++it) 213 (*it)->AddData(data, dataSize); 214 } 215 216 void R5000Device::SetLastChannel(const uint channel) 217 { 218 m_buffer_cleared = (channel == m_last_channel); 219 m_last_channel = channel; 220 221 VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2") 222 .arg(channel).arg(m_buffer_cleared ? "yes" : "no")); 223 } 224 225 void R5000Device::ProcessPATPacket(const TSPacket &tspacket) 226 { 227 if (!tspacket.TransportError() && !tspacket.ScramplingControl() && 228 tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID()) 229 { 230 PESPacket pes = PESPacket::View(tspacket); 231 uint crc = pes.CalcCRC(); 232 m_buffer_cleared |= (crc != m_last_crc); 233 m_last_crc = crc; 234 #if 0 235 VERBOSE(VB_RECORD, LOC + 236 QString("ProcessPATPacket: CRC 0x%1 cleared: %2") 237 .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no")); 238 #endif 239 } 240 else 241 { 242 VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's"); 243 } 244 } 245 246 QString R5000Device::GetModelName(uint vendor_id, uint model_id) 247 { 248 QMutexLocker locker(&s_static_lock); 249 /* 250 if (s_id_to_model.empty()) 251 fw_init(s_id_to_model); 252 253 QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id]; 254 255 if (ret.isEmpty()) 256 return "GENERIC"; 257 */ 258 return "R5000"; 259 } 260 261 bool R5000Device::IsSTBSupported(const QString &panel_model) 262 { 263 return true; 264 } 265 266 bool R5000Device::OpenPort(void) 267 { 268 VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread"); 269 QMutexLocker mlocker(&m_lock); 270 VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread -- locked"); 271 if(usbdev) { 272 m_open_port_cnt++; 273 return true; 274 } 275 276 if(m_serial) { 277 VERBOSE(VB_RECORD, LOC + "Opening R5000 device with serial#: "+ m_serial); 278 usbdev = r5000_open(r5000_device_tspacket_handler, this, m_serial.ascii()); 279 } else { 280 VERBOSE(VB_RECORD, LOC + "Opening R5000 device with unknown serial#"); 281 usbdev = r5000_open(r5000_device_tspacket_handler, this, NULL); 282 } 283 if(! usbdev) 284 return false; 285 286 VERBOSE(VB_RECORD, LOC + "Starting port handler thread"); 287 m_priv->run_port_handler = true; 288 pthread_create(&m_priv->port_handler_thread, NULL, 289 r5000_device_port_handler_thunk, this); 290 291 VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to start"); 292 while (!m_priv->is_port_handler_running) 293 { 294 m_lock.unlock(); 295 usleep(5000); 296 m_lock.lock(); 297 } 298 299 VERBOSE(VB_RECORD, LOC + "Port handler thread started"); 300 301 m_open_port_cnt++; 302 303 return true; 304 } 305 306 bool R5000Device::ClosePort(void) 307 { 308 VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread"); 309 QMutexLocker locker(&m_priv->start_stop_port_handler_lock); 310 VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread -- locked"); 311 312 QMutexLocker mlocker(&m_lock); 313 314 VERBOSE(VB_RECORD, LOC + "ClosePort()"); 315 316 if (m_open_port_cnt < 1) 317 return false; 318 319 m_open_port_cnt--; 320 321 if (m_open_port_cnt != 0) 322 return true; 323 324 if (!usbdev) 325 return false; 326 327 VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to stop"); 328 m_priv->run_port_handler = false; 329 while (m_priv->is_port_handler_running) 330 { 331 m_lock.unlock(); 332 usleep(5000); 333 m_lock.lock(); 334 } 335 VERBOSE(VB_RECORD, LOC + "Joining port handler thread"); 336 pthread_join(m_priv->port_handler_thread, NULL); 337 338 r5000_close(usbdev); 339 usbdev = NULL; 340 341 return true; 342 } 343 344 void *r5000_device_port_handler_thunk(void *param) 345 { 346 R5000Device *mon = (R5000Device*) param; 347 mon->RunPortHandler(); 348 return NULL; 349 } 350 351 void R5000Device::RunPortHandler(void) 352 { 353 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start"); 354 m_lock.lock(); 355 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock"); 356 m_priv->is_port_handler_running = true; 357 m_lock.unlock(); 358 359 while (m_priv->run_port_handler) 360 { 361 if (m_priv->is_streaming) { 362 // This will timeout after 10ms regardless of data availability 363 r5000_loop_iterate(usbdev, 10); 364 } else { 365 usleep(10000); 366 } 367 } 368 369 m_lock.lock(); 370 m_priv->is_port_handler_running = false; 371 m_lock.unlock(); 372 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end"); 373 } 374 375 QStringList R5000Device::GetSTBList(void) 376 { 377 QStringList STBList; 378 int i; 379 r5kenum_t r5k_stbs; 380 r5000_find_stbs(&r5k_stbs); 381 for (i = 0; i < r5k_stbs.count; i++) 382 STBList.append((char *)r5k_stbs.serial[i]); 383 return STBList; 384 } -
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 FireWireDBOptions &firewire_opts); 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(QString serial, uint subunitid, uint speed); 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 void BroadcastToListeners( 78 const unsigned char *data, uint dataSize); 79 80 protected: 81 82 bool GetSubunitInfo(uint8_t table[32]); 83 84 void SetLastChannel(uint channel); 85 void ProcessPATPacket(const TSPacket&); 86 bool StartStreaming(void); 87 bool StopStreaming(void); 88 89 QString m_serial; 90 uint m_subunitid; 91 uint m_speed; 92 uint m_last_channel; 93 uint m_last_crc; 94 bool m_buffer_cleared; 95 96 uint m_open_port_cnt; 97 vector<TSDataListener*> m_listeners; 98 mutable QMutex m_lock; 99 100 /// Vendor ID + Model ID to R5000Device STB model string 101 static QMap<uint64_t,QString> s_id_to_model; 102 static QMutex s_static_lock; 103 private: 104 r5kdev_t *usbdev; 105 R5kPriv *m_priv; 106 }; 107 108 #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 //#define R5K_DEBUG 2 #include <stdio.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 #include <string.h> 7 #include <errno.h> 8 9 #include <sys/time.h> 10 #include <time.h> 11 12 13 #include <usb.h> 14 #include <linux/usbdevice_fs.h> 15 #include "libusb_augment.h" 16 #include "r5000buttons.h" 17 18 #define R5K_WARM_VID 0x0547 19 #define R5K_WARM_PID 0x1002 20 21 #define MAX_URBS_IN_FLIGHT 128 22 #define R5K_URB_BUFFER_SIZE (1 << 14) 23 #define R5K_MAX_PIDS 10 24 25 struct r5kdev { 26 usb_dev_handle *handle; 27 struct usbdevfs_urb *urbs; 28 unsigned char *buffer; 29 unsigned char leftover[188]; 30 unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data); 31 void *cb_data; 32 int nexturb; 33 int streaming; 34 int offset; 35 int bytes_read; 36 #ifdef R5K_DEBUG 37 int fd; 38 #endif 39 unsigned char pmt_pkt[188]; 40 unsigned char num_pmt_entries; 41 unsigned char pmt_state; 42 unsigned char pmt_next_cc; 43 struct { 44 int pid; 45 unsigned char id; 46 } pmt[R5K_MAX_PIDS]; 47 } r5kdev_t; 48 #define r5kdev_t struct r5kdev 49 #include "r5000.h" 50 51 static r5kdev_t *glbl_r5kdev; 52 static int r5000_usb_init = 0; 53 static unsigned char r5000_pat_pkt[188] = { 54 0x47, 0x40, 0x00, 0x13, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x06, 0xc5, 0x00, 0x00, 0x00, 0x01, 0xe0, 55 0x21, 0x19, 0x3a, 0x82, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 56 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 57 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 58 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 60 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 61 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 63 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 64 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 65 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 66 enum { 67 R5K_PMT_START = 0x01, 68 R5K_PMT_READY = 0x02 69 }; 70 #if 0 71 static int r5000_pmt_state = 0; 72 static unsigned char r5000_pmt[188]; 73 static int r5000_pmt_count = 0; 74 static unsigned char r5000_pmt_partial[188*20]; 75 static int r5000_pmt_partial_count = 0; 76 static int r5000_pmt_cc; 77 #endif 78 79 int r5000_create_urbs(r5kdev_t *r5kdev) 80 { 81 int i; 82 r5kdev->urbs = (struct usbdevfs_urb *)malloc(sizeof(struct usbdevfs_urb) * MAX_URBS_IN_FLIGHT); 83 r5kdev->buffer = malloc(R5K_URB_BUFFER_SIZE * MAX_URBS_IN_FLIGHT); 84 for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) { 85 usb_bulk_setup(&r5kdev->urbs[i], 0x82, r5kdev->buffer + (R5K_URB_BUFFER_SIZE*i), R5K_URB_BUFFER_SIZE); 86 } 87 r5kdev->nexturb = 0; 88 return 0; 89 } 90 91 int r5000_free_urbs(r5kdev_t *r5kdev) 92 { 93 free(r5kdev->urbs); 94 free(r5kdev->buffer); 95 return 0; 96 } 97 98 usb_dev_handle *r5000_locate_device( 99 unsigned short vendor_id, unsigned short product_id, int skip) 100 { 101 struct usb_bus *bus; 102 struct usb_device *dev; 103 usb_dev_handle *device_handle = 0; 104 usb_find_busses(); 105 usb_find_devices(); 106 107 for (bus = usb_get_busses(); bus && !device_handle; bus = bus->next) 108 { 109 for (dev = bus->devices; dev && !device_handle; dev = dev->next) 110 { 111 if (dev->descriptor.idVendor == vendor_id && 112 dev->descriptor.idProduct == product_id) 113 { 114 device_handle = usb_open(dev); 115 if(device_handle && skip) { 116 usb_close(device_handle); 117 device_handle = NULL; 118 skip--; 119 } 120 //else { 121 // printf("XSV Device Found @ Address %s \n", dev->filename); 122 // printf("XSV Vendor ID 0x0%x\n",dev->descriptor.idVendor); 123 // printf("XSV Product ID 0x0%x\n",dev->descriptor.idProduct); 124 //} 125 } 126 } 127 } 128 129 if (device_handle) { 130 int open_status = usb_set_configuration(device_handle,1); 131 //printf("conf_stat=%d\n",open_status); 132 133 open_status = usb_claim_interface(device_handle,0); 134 //printf("claim_stat=%d\n",open_status); 135 136 open_status = usb_set_altinterface(device_handle,0); 137 //printf("alt_stat=%d\n",open_status); 138 } 139 return (device_handle); 140 } 141 142 int r5000_get_serial_number(r5kdev_t *r5kdev, char serial[8]) 143 { 144 unsigned char cmd1[] = { 145 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 149 }; 150 unsigned char cmd2[] = { 151 0x08, 0x01, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 155 }; 156 int len; 157 unsigned char buf[0x40]; 158 usb_bulk_read(r5kdev->handle, 129, buf, 0x40, 5000); 159 usb_bulk_write(r5kdev->handle, 1, cmd1, sizeof(cmd1), 5000); 160 usleep(100000); 161 usb_bulk_read(r5kdev->handle, 129, buf, 0x40, 5000); 162 163 usb_bulk_write(r5kdev->handle, 1, cmd2, sizeof(cmd2), 5000); 164 usleep(100000); 165 len = usb_bulk_read(r5kdev->handle, 129, buf, 0x40, 5000); 166 167 if (len == 0x16 && buf[0] == 0x08) { 168 //The device responded appropriately 169 memcpy(serial, buf+6, 7); 170 serial[7] = 0; 171 return 1; 172 } 173 return 0; 174 } 175 176 int r5000_start_stream(r5kdev_t *r5kdev) 177 { 178 unsigned char data[0x80]; 179 int bytes; 180 int i; 181 struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 182 183 if(! r5kdev->urbs) 184 r5000_create_urbs(r5kdev); 185 /* 186 data[0] = 0x20; 187 usb_bulk_write(handle, 1, data, 1, 5000); 188 189 bytes = usb_bulk_read(handle, 129, data, 4, 5000); 190 bytes = usb_bulk_read(handle, 129, data, 128, 5000); 191 */ 192 data[0] = 0x30; 193 usb_bulk_write(handle, 1, data, 1, 5000); 194 bytes = usb_bulk_read(handle, 129, data, 2, 5000); 195 196 data[0] = 0x50; 197 usb_bulk_write(handle, 1, data, 1, 5000); 198 199 for(i=0; i < MAX_URBS_IN_FLIGHT; i++) { 200 usb_urb_submit(handle, &r5kdev->urbs[i], NULL); 201 } 202 r5kdev->nexturb = 0; 203 r5kdev->streaming = 1; 204 r5kdev->offset = 0; 205 return 1; 206 } 207 208 int r5000_stop_stream(r5kdev_t *r5kdev) 209 { 210 struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 211 struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs; 212 int i; 213 214 if(r5kdev->streaming) { 215 for(i=0; i < MAX_URBS_IN_FLIGHT; i++) 216 usb_urb_cancel(handle, &urbs[i]); 217 r5kdev->streaming = 0; 218 } 219 return 0; 220 } 221 222 r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, const char *serial) 223 { 224 r5kdev_t *r5kdev; 225 struct usb_dev_handle *handle; 226 int count = 0; 227 228 if(! r5000_usb_init) { 229 usb_init(); 230 r5000_usb_init = 1; 231 } 232 233 while(count < R5K_MAX_DEVS) { 234 handle = r5000_locate_device(R5K_WARM_VID, R5K_WARM_PID, count); 235 if(! handle); 236 break; 237 if(serial) { 238 char ser1[8]; 239 r5kdev_t r5kdevtmp; 240 r5kdevtmp.handle = handle; 241 if(r5000_get_serial_number(&r5kdevtmp, ser1)) { 242 if(memcmp(serial, ser1, 8) == 0) 243 break; 244 count++; 245 } 246 usb_close(handle); 247 } else 248 break; 249 } 250 if(! handle) 251 return NULL; 252 r5kdev = (r5kdev_t *)calloc(1, sizeof(r5kdev_t)); 253 r5kdev->handle = handle; 254 r5kdev->urbs = NULL; 255 r5kdev->cb = cb; 256 r5kdev->cb_data = cb_data; 257 #ifdef R5K_DEBUG 258 r5kdev->fd = open("r5kdebug.raw", O_WRONLY | O_TRUNC | O_CREAT, 0666); 259 #endif 260 glbl_r5kdev = r5kdev; 261 return r5kdev; 262 } 263 264 int r5000_close(r5kdev_t *r5kdev) 265 { 266 if(! r5kdev) 267 return 0; 268 if(r5kdev->urbs) { 269 if(r5kdev->streaming) 270 r5000_stop_stream(r5kdev); 271 r5000_free_urbs(r5kdev); 272 } 273 #ifdef R5K_DEBUG 274 if(r5kdev->fd >= 0) 275 close(r5kdev->fd); 276 #endif 277 usb_close(r5kdev->handle); 278 free(r5kdev); 279 return 0; 280 } 281 #if 0 282 void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf) 283 { 284 int pid = ((buf[1] << 8) | buf[2]) & 0x1fff; 285 if(pid == 0x00 && r5000_pmt_state & R5K_PMT_READY) { 286 int i; 287 for(i = 0; i < r5000_pmt_count; i++) { 288 unsigned char *ptr = r5000_pmt + 188*i; 289 r5000_pmt_cc = (r5000_pmt_cc +1) &0xf; 290 ptr[3] = (ptr[3] & 0xf0) | r5000_pmt_cc; 291 r5kdev->cb(ptr, 188, r5kdev->cb_data); 292 } 293 } else if(pid == 0x21) { 294 r5000_pmt_cc = buf[3] & 0xf; 295 if(buf[1] & 0x40 && buf[4] == 0x00 && buf[5] == 0x02) { 296 if(r5000_pmt_state & R5K_PMT_START) { 297 memcpy(r5000_pmt, r5000_pmt_partial, 188 * r5000_pmt_partial_count); 298 r5000_pmt_count = r5000_pmt_partial_count; 299 r5000_pmt_state |= R5K_PMT_READY; 300 } 301 memcpy(r5000_pmt_partial, buf, 188); 302 r5000_pmt_partial_count = 1; 303 r5000_pmt_state |= R5K_PMT_START; 304 } else if(r5000_pmt_state & R5K_PMT_START) { 305 memcpy(r5000_pmt_partial + 188*r5000_pmt_partial_count, buf, 188); 306 r5000_pmt_partial_count++; 307 } 308 } 309 } 310 #else 311 //taken and adapted from libdtv, (c) Rolf Hakenes 312 // CRC32 lookup table for polynomial 0x04c11db7 313 static unsigned int crc_table[256] = { 314 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 315 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 316 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 317 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 318 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 319 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 320 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 321 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 322 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 323 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 324 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 325 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 326 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 327 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 328 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 329 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 330 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 331 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 332 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 333 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 334 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 335 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 336 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 337 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 338 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 339 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 340 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 341 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 342 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 343 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 344 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 345 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 346 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 347 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 348 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 349 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 350 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 351 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 352 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 353 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 354 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 355 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 356 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; 357 358 void r5000_calc_crc(unsigned char *out, const unsigned char *d, int len) 359 { 360 register int i; 361 unsigned int crc = 0xFFFFFFFF; 362 const unsigned char *u=(unsigned char*)d; // Saves '& 0xff' 363 364 for (i=0; i<len; i++) 365 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)]; 366 367 *out++ = (crc >> 24) & 0xff; 368 *out++ = (crc >> 16) & 0xff; 369 *out++ = (crc >> 8) & 0xff; 370 *out++ = (crc >> 0) & 0xff; 371 } 372 373 #define IS_VIDEO(x) ((x) == 0x02 || (x) == 0x1b) 374 void r5000_send_pmt(r5kdev_t *r5kdev) 375 { 376 if(r5kdev->pmt_pkt[0] != 0x47) { 377 int i; 378 unsigned char *ptr; 379 unsigned char ts[188] = { 380 0x47, 0x40, 0x21, 0x10, 381 0x00, 0x02, 382 0xb0, 0x00, //length 383 0x00, 0x01, 384 0xc3, 0x00, 0x00, 385 0xf0, 0x00, //PCR_PID 386 0xf0, 0x00}; //Program Info Length 387 ts[3] = 0x10 | r5kdev->pmt_next_cc; 388 printf("Building PMT\n"); 389 ptr = ts + 17; 390 for(i = 0; i < r5kdev->num_pmt_entries; i++) { 391 *ptr++ = r5kdev->pmt[i].id; 392 *ptr++ = 0xe0 | (r5kdev->pmt[i].pid>>8); 393 *ptr++ = r5kdev->pmt[i].pid & 0xff; 394 *ptr++ = 0xf0; 395 if(IS_VIDEO(r5kdev->pmt[i].id)) { 396 *ptr++ = 0x00; 397 ts[13] = 0xe0 | (r5kdev->pmt[i].pid >> 8); 398 ts[14] = r5kdev->pmt[i].pid & 0xff; 399 } else { 400 *ptr++ = 0x06; 401 *ptr++ = 0x0a; 402 *ptr++ = 0x04; 403 *ptr++ = 0x65; 404 *ptr++ = 0x6e; 405 *ptr++ = 0x67; 406 *ptr++ = 0x00; 407 } 408 } 409 ts[7] = (ptr - ts) - 8/*header*/ + 4/*CRC*/; 410 r5000_calc_crc(ptr, ts + 5, (ptr - ts) - 5); 411 memset(ptr+4, 0xff, 188 - (ptr - ts - 4)); 412 memcpy(r5kdev->pmt_pkt, ts, 188); 413 } 414 r5kdev->pmt_pkt[3] = 0x10 | r5kdev->pmt_next_cc; 415 r5kdev->pmt_next_cc = (r5kdev->pmt_next_cc + 1) & 0x0f; 416 r5kdev->cb(r5kdev->pmt_pkt, 188, r5kdev->cb_data); 417 } 418 419 void r5000_add_pmt(r5kdev_t *r5kdev, int pid, int table_id) 420 { 421 int i; 422 int is_video = IS_VIDEO(table_id); 423 424 for(i = 0; i < r5kdev->num_pmt_entries; i++) { 425 if(r5kdev->pmt[i].pid == pid) { 426 if(r5kdev->pmt[i].id == table_id) 427 return; 428 //different table_id for existing pid. Reset 429 r5kdev->num_pmt_entries = 0; 430 r5kdev->pmt_state = 0; 431 r5kdev->pmt_pkt[0] = 0; 432 break; 433 } 434 if(is_video) { 435 if(IS_VIDEO(r5kdev->pmt[i].id)) { 436 //a video entry already exists. Reset 437 r5kdev->num_pmt_entries = 0; 438 r5kdev->pmt_state = 0; 439 r5kdev->pmt_pkt[0] = 0; 440 break; 441 } 442 } 443 } 444 //Didn't find this PID, add it 445 if(i == R5K_MAX_PIDS) 446 return; 447 printf("Adding %04x: %02x @ %08x\n", pid, table_id, r5kdev->bytes_read); 448 r5kdev->pmt[r5kdev->num_pmt_entries].pid = pid; 449 r5kdev->pmt[r5kdev->num_pmt_entries].id = table_id; 450 r5kdev->num_pmt_entries++; 451 r5kdev->pmt_state |= is_video ? 0x01 : 0x02; 452 } 453 454 void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf) 455 { 456 int stream_id, pid, afc, af_size = 0; 457 pid = ((buf[1] << 8) | buf[2]) & 0x1fff; 458 if(pid == 0x1fff) 459 return; 460 if(pid == 0) { 461 r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data); 462 if(r5kdev->pmt_state == 0x03) 463 r5000_send_pmt(r5kdev); 464 } else { 465 if(pid != 0x21) 466 r5kdev->cb(buf, 188, r5kdev->cb_data); 467 //Only interested in PES packets starting in this TS packet 468 if (!buf[1] & 0x40) 469 return; 470 afc = (buf[3]>>4) & 0x03; 471 if(afc == 0x2) 472 return; 473 if(afc == 0x3) 474 af_size = buf[4]+1; 475 if(buf[4+af_size] != 0x00 || buf[5+af_size] != 0x00 || buf[6+af_size] != 0x01) 476 return; 477 //We have a PES packet 478 stream_id = buf[7+af_size]; 479 if((stream_id & 0xf0) == 0xe0) { 480 //Video stream (we need the adaptation field) 481 if(afc != 0x03) 482 return; 483 if(0) { 484 int i; 485 for(i = 0; i < af_size+8; i++) { 486 printf("%02x ", buf[i]); 487 if((i %16) == 15) 488 printf("\n"); 489 } 490 printf("\n"); 491 } 492 if(buf[5] & 0x02) { 493 // Has private data, this is MPEG4 494 r5000_add_pmt(r5kdev, pid, 0x1b); 495 } else if(buf[5] & 0x10) { 496 // Has PCR and no private data, this is MPEG2 497 r5000_add_pmt(r5kdev, pid, 0x02); 498 } 499 } else if((stream_id & 0xf0) == 0xc0) { 500 //Audio stream 501 r5000_add_pmt(r5kdev, pid, 0x04); 502 } else if(stream_id == 0xbd) { 503 //Audio stream 504 r5000_add_pmt(r5kdev, pid, 0x81); 505 } 506 } 507 } 508 #endif 509 void r5000_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len) 510 { 511 int pos; 512 int sync = 1; 513 if(! r5kdev->streaming) 514 return; 515 if(len <= 0) 516 return; 517 518 pos = r5kdev->offset; 519 #ifdef R5K_DEBUG 520 if(r5kdev->fd >= 0) 521 write(r5kdev->fd, buf, len); 522 #endif 523 while(pos < len) { 524 if(buf[pos] != 0x47 || (pos <len-1 && buf[pos+1] == 0xff)) 525 goto nosync; 526 // If we get here, buf[pos] == 0x47 527 if(r5kdev->offset) { 528 //previous data exists and is part of a good packet 529 memcpy(r5kdev->leftover+188-r5kdev->offset, buf, r5kdev->offset); 530 r5000_force_pmt(r5kdev, r5kdev->leftover); 531 r5kdev->offset = 0; 532 } 533 if(pos+188 < len) { 534 //at least one full packet is available 535 if(buf[pos+188] != 0x47) 536 goto nosync; 537 } else { 538 //Out of data, but the partial packet may be ok. 539 memcpy(r5kdev->leftover, buf+pos, len-pos); 540 r5kdev->offset = 188-(len-pos); 541 break; 542 } 543 //If we get here, we have a good packet 544 r5000_force_pmt(r5kdev, buf+pos); 545 if(! sync) 546 printf("(%d) Found sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos); 547 sync = 1; 548 pos+=188; 549 continue; 550 nosync: 551 r5kdev->offset=0; 552 if(sync) 553 printf("(%d)Lost sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos); 554 sync = 0; 555 pos++; 556 } 557 r5kdev->bytes_read += len; 558 } 559 560 int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec) 561 { 562 struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 563 struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs; 564 int len; 565 unsigned char *buf; 566 struct timeval tv1, tv2; 567 if(! r5kdev->streaming) 568 return -1; 569 gettimeofday(&tv1, NULL); 570 len = usb_urb_reap(handle, &urbs[r5kdev->nexturb], timeout_usec); 571 gettimeofday(&tv2, NULL); 572 //printf("%u.%06u (%u.%06u) Read %d bytes\n", (unsigned int)tv1.tv_sec, (unsigned int)tv1.tv_usec, (unsigned int)tv2.tv_sec, (unsigned int)tv2.tv_usec, len); 573 if(len <= 0) { 574 if(len != -ETIMEDOUT) 575 printf("(%d) Reap failed at %08x: %s\n", r5kdev->nexturb, r5kdev->bytes_read, strerror(errno)); 576 return len; 577 } 578 buf = r5kdev->buffer + (R5K_URB_BUFFER_SIZE*r5kdev->nexturb); 579 r5000_process_block(r5kdev, buf, len); 580 usb_urb_submit(handle, &urbs[r5kdev->nexturb], NULL); 581 r5kdev->nexturb = (r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT; 582 return 0; 583 } 584 585 int r5000_read_status(r5kdev_t *r5kdev, unsigned char *buf) 586 { 587 return usb_bulk_read(r5kdev->handle, 129, buf, 128, 5000); 588 } 589 590 int r5000_get_power_state(r5kdev_t *r5kdev) 591 { 592 unsigned char data1[1] = { 0x30 }; 593 unsigned char data2[0x80]; 594 while(1) { 595 r5000_read_status(r5kdev, data2); 596 usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000); 597 usleep(100000); 598 if(usb_bulk_read(r5kdev->handle, 1, data2, 2, 5000) == 2 && 599 data2[0] == 0x0a && (data2[1] & 0x4e) == 0x4c) 600 return (!!(data2[1] == 0x4d)); 601 usleep(100000); 602 } 603 } 604 605 int r5000_toggle_on_off(r5kdev_t *r5kdev) 606 { 607 unsigned char data1[1] = { 0x30 }; 608 unsigned char data3[0x80], on_off; 609 int len; 610 on_off = r5000_get_power_state(r5kdev); 611 //printf("Start state: %s\n", on_off ? "On" : "Off"); 612 usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000); 613 usleep(100000); 614 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_POWER], 0x40, 5000); 615 usleep(100000); 616 len = usb_bulk_read(r5kdev->handle, 1, data3, 2, 5000); 617 usleep(100000); 618 while(r5000_get_power_state(r5kdev) == on_off) 619 usleep(100000); 620 //printf("End state: %s\n", !on_off ? "On" : "Off"); 621 return !on_off; 622 } 623 624 void r5000_change_channel(r5kdev_t *r5kdev, int chan) 625 { 626 int pos = 1000000, digit; 627 unsigned char data2[0x80]; 628 r5000_read_status(r5kdev, data2); 629 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_CLEAR], 0x40, 5000); 630 usleep(R5000_BUTTON_DELAY); 631 while(pos != 0 && (chan/pos) == 0) 632 pos /= 10; 633 if(pos == 0) 634 pos = 1; 635 while(pos != 0) { 636 digit = chan / pos; 637 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[digit], 0x40, 5000); 638 chan -= digit*pos; 639 pos/= 10; 640 usleep(R5000_BUTTON_DELAY); 641 } 642 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_ENTER], 0x40, 5000); 643 } 644 645 void r5000_find_stbs(r5kenum_t *devs) 646 { 647 r5kdev_t r5kdev; 648 devs->count = 0; 649 if(! r5000_usb_init) { 650 usb_init(); 651 r5000_usb_init = 1; 652 } 653 while(devs->count < R5K_MAX_DEVS) { 654 r5kdev.handle = r5000_locate_device(R5K_WARM_VID, R5K_WARM_PID, devs->count); 655 if(! r5kdev.handle) 656 break; 657 if(r5000_get_serial_number(&r5kdev, devs->serial[devs->count])) 658 devs->count++; 659 usb_close(r5kdev.handle); 660 } 661 } -
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 extern r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, const char *serial); 15 extern int r5000_close(r5kdev_t *r5kdev); 16 extern int r5000_start_stream(r5kdev_t *r5kdev); 17 extern int r5000_stop_stream(r5kdev_t *r5kdev); 18 extern int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec); 19 extern int r5000_get_power_state(r5kdev_t *r5kdev); 20 extern int r5000_toggle_on_off(r5kdev_t *r5kdev); 21 extern void r5000_change_channel(r5kdev_t *r5kdev, int chan); 22 extern void r5000_find_stbs(r5kenum_t *devs); 23 #endif //R5000_H -
new file libs/libmythtv/r5000/r5000buttons.h
- + 1 ///This has only been verified for a VIP211. Quite possibly different buttons are needed for different receivers. 2 // 3 #define R5000_BUTTON_DELAY 400000 4 enum { 5 R5K_BUTTON_0 = 0, 6 R5K_BUTTON_1, 7 R5K_BUTTON_2, 8 R5K_BUTTON_3, 9 R5K_BUTTON_4, 10 R5K_BUTTON_5, 11 R5K_BUTTON_6, 12 R5K_BUTTON_7, 13 R5K_BUTTON_8, 14 R5K_BUTTON_9, 15 R5K_BUTTON_CLEAR, 16 R5K_BUTTON_ENTER, 17 R5K_BUTTON_POWER, 18 R5K_BUTTON_MAX 19 }; 20 const unsigned char r5000_button_cmd[R5K_BUTTON_MAX][0x40] = 21 { 22 //button 0: 23 { 24 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 25 0x04, 0x1a, 0x04, 0x0e, 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, 0x0e, 0x04, 0x1a, 27 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 28 }, 29 //button 1: 30 { 31 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 32 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 35 }, 36 //button 2: 37 { 38 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 39 0x04, 0x1a, 0x04, 0x0e, 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, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 42 }, 43 //button 3: 44 { 45 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 46 0x04, 0x0e, 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, 0x1a, 48 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 49 }, 50 //button 4: 51 { 52 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 53 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 56 }, 57 //button 5: 58 { 59 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 60 0x04, 0x1a, 0x04, 0x0e, 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, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 63 }, 64 //button 6: 65 { 66 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 67 0x04, 0x0e, 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, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 70 }, 71 //button 7: 72 { 73 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 74 0x04, 0x1a, 0x04, 0x1a, 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, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 77 }, 78 //button 8: 79 { 80 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 81 0x04, 0x1a, 0x04, 0x0e, 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, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 84 }, 85 //button 9: 86 { 87 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 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, 0x1a, 0x04, 0x0e, 90 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 91 }, 92 //Clear: 93 { 94 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 95 0x04, 0x0e, 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, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 98 }, 99 //Enter: 100 { 101 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 102 0x04, 0x1a, 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, 0x0e, 0x04, 0x1a, 104 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 105 }, 106 //Power 107 { 108 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 109 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 110 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 111 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 112 } 113 };