Ticket #4752: r5000_r1.patch
| File r5000_r1.patch, 92.2 KB (added by anonymous, 4 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 1297 1297 } 1298 1298 }; 1299 1299 1300 class R5000ConfigurationGroup : public VerticalConfigurationGroup 1301 { 1302 public: 1303 R5000ConfigurationGroup(CaptureCard& a_parent): 1304 VerticalConfigurationGroup(false, true, false, false), 1305 parent(a_parent) 1306 { 1307 setUseLabel(false); 1308 addChild(new SignalTimeout(parent, 2000, 1000)); 1309 addChild(new ChannelTimeout(parent, 9000, 1750)); 1310 addChild(new SingleCardInput(parent)); 1311 }; 1312 1313 private: 1314 CaptureCard &parent; 1315 }; 1316 1300 1317 class IPTVHost : public LineEditSetting, public CaptureCardDBStorage 1301 1318 { 1302 1319 public: … … 1481 1498 #ifdef USING_IPTV 1482 1499 addTarget("FREEBOX", new IPTVConfigurationGroup(parent)); 1483 1500 #endif // USING_IPTV 1501 1502 #ifdef USING_R5000 1503 addTarget("R5000", new R5000ConfigurationGroup(parent)); 1504 #endif // USING_R5000 1484 1505 } 1485 1506 1486 1507 void CaptureCardGroup::triggerChanged(const QString& value) … … 1668 1689 #ifdef USING_IPTV 1669 1690 setting->addSelection(QObject::tr("Network Recorder"), "FREEBOX"); 1670 1691 #endif // USING_IPTV 1692 1693 #ifdef USING_R5000 1694 setting->addSelection(QObject::tr("R5000 Capable STB"), "R5000"); 1695 #endif // USING_R5000 1671 1696 } 1672 1697 1673 1698 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 uint subunitid = 0; // we only support first tuner on STB... 25 26 device = new R5000Device(0, subunitid, fw_opts.speed); 27 28 InitializeInputs(); 29 } 30 31 bool R5000Channel::SetChannelByString(const QString &channum) 32 { 33 QString loc = LOC + QString("SetChannelByString(%1)").arg(channum); 34 bool ok = true; 35 VERBOSE(VB_CHANNEL, loc); 36 37 InputMap::const_iterator it = inputs.find(currentInputID); 38 if (it == inputs.end()) 39 return false; 40 41 QString tvformat, modulation, freqtable, freqid, dtv_si_std; 42 int finetune; 43 uint64_t frequency; 44 int mpeg_prog_num; 45 uint atsc_major, atsc_minor, mplexid, tsid, netid; 46 if (!ChannelUtil::GetChannelData( 47 (*it)->sourceid, channum, 48 tvformat, modulation, freqtable, freqid, 49 finetune, frequency, 50 dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid, 51 mplexid, commfree)) 52 { 53 VERBOSE(VB_IMPORTANT, loc + " " + QString( 54 "Requested channel '%1' is on input '%2' " 55 "which is in a busy input group") 56 .arg(channum).arg(currentInputID)); 57 58 return false; 59 } 60 uint mplexid_restriction; 61 if (!IsInputAvailable(currentInputID, mplexid_restriction)) 62 { 63 VERBOSE(VB_IMPORTANT, loc + " " + QString( 64 "Requested channel '%1' is on input '%2' " 65 "which is in a busy input group") 66 .arg(channum).arg(currentInputID)); 67 68 return false; 69 } 70 71 uint ichan = freqid.toUInt(&ok); 72 ok = isopen && SetChannelByNumber(ichan); 73 74 if (ok) 75 { 76 // Set the current channum to the new channel's channum 77 curchannelname = QDeepCopy<QString>(channum); 78 (*it)->startChanNum = QDeepCopy<QString>(channum); 79 } 80 81 VERBOSE(VB_CHANNEL, loc + " " + ((ok) ? "success" : "failure")); 82 83 return ok; 84 } 85 86 bool R5000Channel::Open(void) 87 { 88 VERBOSE(VB_CHANNEL, LOC + "Open()"); 89 90 if (inputs.find(currentInputID) == inputs.end()) 91 return false; 92 93 if (!device) 94 return false; 95 96 if (isopen) 97 return true; 98 99 if (!device->OpenPort()) 100 return false; 101 102 isopen = true; 103 104 return true; 105 } 106 107 void R5000Channel::Close(void) 108 { 109 VERBOSE(VB_CHANNEL, LOC + "Close()"); 110 if (isopen) 111 { 112 device->ClosePort(); 113 isopen = false; 114 } 115 } 116 117 QString R5000Channel::GetDevice(void) const 118 { 119 return videodevice; 120 } 121 122 bool R5000Channel::SetPowerState(bool on) 123 { 124 if (!isopen) 125 { 126 VERBOSE(VB_IMPORTANT, LOC_ERR + 127 "SetPowerState() called on closed R5000Channel."); 128 129 return false; 130 } 131 132 return device->SetPowerState(on); 133 } 134 135 R5000Device::PowerState R5000Channel::GetPowerState(void) const 136 { 137 if (!isopen) 138 { 139 VERBOSE(VB_IMPORTANT, LOC_ERR + 140 "GetPowerState() called on closed R5000Channel."); 141 142 return R5000Device::kAVCPowerQueryFailed; 143 } 144 145 return device->GetPowerState(); 146 } 147 148 bool R5000Channel::Retune(void) 149 { 150 VERBOSE(VB_CHANNEL, LOC + "Retune()"); 151 152 if (R5000Device::kAVCPowerOff == GetPowerState()) 153 { 154 VERBOSE(VB_IMPORTANT, LOC_ERR + 155 "STB is turned off, must be on to retune."); 156 157 return false; 158 } 159 160 if (current_channel) 161 return SetChannelByNumber(current_channel); 162 163 return false; 164 } 165 166 bool R5000Channel::SetChannelByNumber(int channel) 167 { 168 VERBOSE(VB_CHANNEL, QString("SetChannelByNumber(%1)").arg(channel)); 169 current_channel = channel; 170 171 if (R5000Device::kAVCPowerOff == GetPowerState()) 172 { 173 VERBOSE(VB_IMPORTANT, LOC_WARN + 174 "STB is turned off, must be on to set channel."); 175 176 SetSIStandard("mpeg"); 177 SetDTVInfo(0,0,0,0,1); 178 179 return true; // signal monitor will call retune later... 180 } 181 182 if (!device->SetChannel(fw_opts.model, 0, channel)) 183 return false; 184 185 SetSIStandard("mpeg"); 186 SetDTVInfo(0,0,0,0,1); 187 188 return true; 189 } -
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 static void fw_init(QMap<uint64_t,QString> &id_to_model); 21 22 QMap<uint64_t,QString> R5000Device::s_id_to_model; 23 QMutex R5000Device::s_static_lock; 24 25 unsigned int r5000_device_tspacket_handler(unsigned char *tspacket, int len, void *callback_data) 26 { 27 R5000Device *fw = (R5000Device*) callback_data; 28 if (! fw) 29 return 0; 30 if (len > 0) 31 fw->BroadcastToListeners(tspacket, len); 32 return 1; 33 } 34 35 36 class R5kPriv 37 { 38 public: 39 R5kPriv() : 40 reset_timer_on(false), 41 run_port_handler(false), is_port_handler_running(false), 42 channel(-1), 43 is_streaming(false) 44 { 45 } 46 47 bool reset_timer_on; 48 MythTimer reset_timer; 49 50 bool run_port_handler; 51 bool is_port_handler_running; 52 QMutex start_stop_port_handler_lock; 53 54 int channel; 55 56 bool is_streaming; 57 58 QDateTime stop_streaming_timer; 59 pthread_t port_handler_thread; 60 61 static QMutex s_lock; 62 }; 63 QMutex R5kPriv::s_lock; 64 65 //callback functions 66 void *r5000_device_port_handler_thunk(void *param); 67 68 R5000Device::R5000Device(uint64_t guid, uint subunitid, uint speed) : 69 m_guid(guid), m_subunitid(subunitid), 70 m_speed(speed), 71 m_last_channel(0), m_last_crc(0), 72 m_buffer_cleared(true), m_open_port_cnt(0), 73 m_lock(false), m_priv(new R5kPriv()) 74 { 75 usbdev = NULL; 76 } 77 78 R5000Device::~R5000Device() 79 { 80 if (usbdev) 81 { 82 VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port"); 83 while(usbdev) 84 ClosePort(); 85 } 86 87 if (m_priv) 88 { 89 delete m_priv; 90 m_priv = NULL; 91 } 92 } 93 94 void R5000Device::AddListener(TSDataListener *listener) 95 { 96 if (listener) 97 { 98 vector<TSDataListener*>::iterator it = 99 find(m_listeners.begin(), m_listeners.end(), listener); 100 101 if (it == m_listeners.end()) 102 m_listeners.push_back(listener); 103 } 104 105 VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size()); 106 if (!m_listeners.empty()) 107 { 108 StartStreaming(); 109 } 110 } 111 112 void R5000Device::RemoveListener(TSDataListener *listener) 113 { 114 vector<TSDataListener*>::iterator it = m_listeners.end(); 115 116 do 117 { 118 it = find(m_listeners.begin(), m_listeners.end(), listener); 119 if (it != m_listeners.end()) 120 m_listeners.erase(it); 121 } 122 while (it != m_listeners.end()); 123 124 VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size()); 125 if (m_listeners.empty()) 126 { 127 StopStreaming(); 128 } 129 } 130 131 bool R5000Device::StartStreaming(void) 132 { 133 if (m_priv->is_streaming) 134 return m_priv->is_streaming; 135 136 if (! usbdev) 137 { 138 VERBOSE(VB_IMPORTANT, LOC_ERR + "Device not open"); 139 return false; 140 } 141 if (r5000_start_stream(usbdev)) 142 { 143 m_priv->is_streaming = true; 144 } 145 else 146 { 147 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming "); 148 } 149 150 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- done"); 151 152 return m_priv->is_streaming; 153 } 154 155 bool R5000Device::StopStreaming(void) 156 { 157 if (m_priv->is_streaming) 158 { 159 VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really"); 160 161 m_priv->is_streaming = false; 162 163 r5000_stop_stream(usbdev); 164 } 165 166 VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming"); 167 168 return true; 169 } 170 171 bool R5000Device::SetPowerState(bool on) 172 { 173 QMutexLocker locker(&m_lock); 174 QString cmdStr = (on) ? "on" : "off"; 175 VERBOSE(VB_RECORD, LOC + QString("Powering %1").arg(cmdStr)); 176 if(r5000_get_power_state(usbdev) != on) 177 r5000_toggle_on_off(usbdev); 178 return true; 179 } 180 181 R5000Device::PowerState R5000Device::GetPowerState(void) 182 { 183 QMutexLocker locker(&m_lock); 184 int on_off; 185 186 VERBOSE(VB_CHANNEL, LOC + "Requesting STB Power State"); 187 on_off = r5000_get_power_state(usbdev); 188 VERBOSE(VB_CHANNEL, LOC + (on_off ? "On" : "Off")); 189 return on_off ? kAVCPowerOn : kAVCPowerOff; 190 } 191 192 bool R5000Device::SetChannel(const QString &panel_model, 193 uint alt_method, uint channel) 194 { 195 VERBOSE(VB_CHANNEL, QString("SetChannel(model %1, alt %2, chan %3)") 196 .arg(panel_model).arg(alt_method).arg(channel)); 197 198 QMutexLocker locker(&m_lock); 199 VERBOSE(VB_CHANNEL, "SetChannel() -- locked"); 200 r5000_change_channel(usbdev, channel); 201 return true; 202 } 203 204 void R5000Device::BroadcastToListeners( 205 const unsigned char *data, uint dataSize) 206 { 207 if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) && 208 ((data[1] & 0x1f) == 0) && (data[2] == 0)) 209 { 210 ProcessPATPacket(*((const TSPacket*)data)); 211 } 212 213 vector<TSDataListener*>::iterator it = m_listeners.begin(); 214 for (; it != m_listeners.end(); ++it) 215 (*it)->AddData(data, dataSize); 216 } 217 218 void R5000Device::SetLastChannel(const uint channel) 219 { 220 m_buffer_cleared = (channel == m_last_channel); 221 m_last_channel = channel; 222 223 VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2") 224 .arg(channel).arg(m_buffer_cleared ? "yes" : "no")); 225 } 226 227 void R5000Device::ProcessPATPacket(const TSPacket &tspacket) 228 { 229 if (!tspacket.TransportError() && !tspacket.ScramplingControl() && 230 tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID()) 231 { 232 PESPacket pes = PESPacket::View(tspacket); 233 uint crc = pes.CalcCRC(); 234 m_buffer_cleared |= (crc != m_last_crc); 235 m_last_crc = crc; 236 #if 0 237 VERBOSE(VB_RECORD, LOC + 238 QString("ProcessPATPacket: CRC 0x%1 cleared: %2") 239 .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no")); 240 #endif 241 } 242 else 243 { 244 VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's"); 245 } 246 } 247 248 QString R5000Device::GetModelName(uint vendor_id, uint model_id) 249 { 250 QMutexLocker locker(&s_static_lock); 251 /* 252 if (s_id_to_model.empty()) 253 fw_init(s_id_to_model); 254 255 QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id]; 256 257 if (ret.isEmpty()) 258 return "GENERIC"; 259 */ 260 return "R5000"; 261 } 262 263 bool R5000Device::IsSTBSupported(const QString &panel_model) 264 { 265 return true; 266 } 267 268 bool R5000Device::OpenPort(void) 269 { 270 VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread"); 271 QMutexLocker mlocker(&m_lock); 272 VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread -- locked"); 273 if(usbdev) { 274 m_open_port_cnt++; 275 return true; 276 } 277 278 usbdev = r5000_open(r5000_device_tspacket_handler, this, 0); 279 if(! usbdev) 280 return false; 281 282 VERBOSE(VB_RECORD, LOC + "Starting port handler thread"); 283 m_priv->run_port_handler = true; 284 pthread_create(&m_priv->port_handler_thread, NULL, 285 r5000_device_port_handler_thunk, this); 286 287 VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to start"); 288 while (!m_priv->is_port_handler_running) 289 { 290 m_lock.unlock(); 291 usleep(5000); 292 m_lock.lock(); 293 } 294 295 VERBOSE(VB_RECORD, LOC + "Port handler thread started"); 296 297 m_open_port_cnt++; 298 299 return true; 300 } 301 302 bool R5000Device::ClosePort(void) 303 { 304 VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread"); 305 QMutexLocker locker(&m_priv->start_stop_port_handler_lock); 306 VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread -- locked"); 307 308 QMutexLocker mlocker(&m_lock); 309 310 VERBOSE(VB_RECORD, LOC + "ClosePort()"); 311 312 if (m_open_port_cnt < 1) 313 return false; 314 315 m_open_port_cnt--; 316 317 if (m_open_port_cnt != 0) 318 return true; 319 320 if (!usbdev) 321 return false; 322 323 VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to stop"); 324 m_priv->run_port_handler = false; 325 while (m_priv->is_port_handler_running) 326 { 327 m_lock.unlock(); 328 usleep(5000); 329 m_lock.lock(); 330 } 331 VERBOSE(VB_RECORD, LOC + "Joining port handler thread"); 332 pthread_join(m_priv->port_handler_thread, NULL); 333 334 r5000_close(usbdev); 335 usbdev = NULL; 336 337 return true; 338 } 339 340 void *r5000_device_port_handler_thunk(void *param) 341 { 342 R5000Device *mon = (R5000Device*) param; 343 mon->RunPortHandler(); 344 return NULL; 345 } 346 347 void R5000Device::RunPortHandler(void) 348 { 349 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start"); 350 m_lock.lock(); 351 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock"); 352 m_priv->is_port_handler_running = true; 353 m_lock.unlock(); 354 355 while (m_priv->run_port_handler) 356 { 357 if (m_priv->is_streaming) { 358 // This will timeout after 10ms regardless of data availability 359 r5000_loop_iterate(usbdev, 10); 360 } else { 361 usleep(10000); 362 } 363 } 364 365 m_lock.lock(); 366 m_priv->is_port_handler_running = false; 367 m_lock.unlock(); 368 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end"); 369 } -
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 // AVC commands 41 typedef enum 42 { 43 kAVCControlCommand = 0x00, 44 kAVCStatusInquiryCommand = 0x01, 45 kAVCSpecificInquiryCommand = 0x02, 46 kAVCNotifyCommand = 0x03, 47 kAVCGeneralInquiryCommand = 0x04, 48 49 kAVCNotImplementedStatus = 0x08, 50 kAVCAcceptedStatus = 0x09, 51 kAVCRejectedStatus = 0x0a, 52 kAVCInTransitionStatus = 0x0b, 53 kAVCImplementedStatus = 0x0c, 54 kAVCChangedStatus = 0x0d, 55 56 kAVCInterimStatus = 0x0f, 57 kAVCResponseImplemented = 0x0c, 58 } IEEE1394Command; 59 60 // AVC unit addresses 61 typedef enum 62 { 63 kAVCSubunitId0 = 0x00, 64 kAVCSubunitId1 = 0x01, 65 kAVCSubunitId2 = 0x02, 66 kAVCSubunitId3 = 0x03, 67 kAVCSubunitId4 = 0x04, 68 kAVCSubunitIdExtended = 0x05, 69 kAVCSubunitIdIgnore = 0x07, 70 71 kAVCSubunitTypeVideoMonitor = (0x00 << 3), 72 kAVCSubunitTypeAudio = (0x01 << 3), 73 kAVCSubunitTypePrinter = (0x02 << 3), 74 kAVCSubunitTypeDiscRecorder = (0x03 << 3), 75 kAVCSubunitTypeTapeRecorder = (0x04 << 3), 76 kAVCSubunitTypeTuner = (0x05 << 3), 77 kAVCSubunitTypeCA = (0x06 << 3), 78 kAVCSubunitTypeVideoCamera = (0x07 << 3), 79 kAVCSubunitTypePanel = (0x09 << 3), 80 kAVCSubunitTypeBulletinBoard = (0x0a << 3), 81 kAVCSubunitTypeCameraStorage = (0x0b << 3), 82 kAVCSubunitTypeMusic = (0x0c << 3), 83 kAVCSubunitTypeVendorUnique = (0x1c << 3), 84 kAVCSubunitTypeExtended = (0x1e << 3), 85 kAVCSubunitTypeUnit = (0x1f << 3), 86 } IEEE1394UnitAddress; 87 88 // AVC opcode 89 typedef enum 90 { 91 // Unit 92 kAVCUnitPlugInfoOpcode = 0x02, 93 kAVCUnitDigitalOutputOpcode = 0x10, 94 kAVCUnitDigitalInputOpcode = 0x11, 95 kAVCUnitChannelUsageOpcode = 0x12, 96 kAVCUnitOutputPlugSignalFormatOpcode = 0x18, 97 kAVCUnitInputPlugSignalFormatOpcode = 0x19, 98 kAVCUnitConnectAVOpcode = 0x20, 99 kAVCUnitDisconnectAVOpcode = 0x21, 100 kAVCUnitConnectionsOpcode = 0x22, 101 kAVCUnitConnectOpcode = 0x24, 102 kAVCUnitDisconnectOpcode = 0x25, 103 kAVCUnitUnitInfoOpcode = 0x30, 104 kAVCUnitSubunitInfoOpcode = 0x31, 105 kAVCUnitSignalSourceOpcode = 0x1a, 106 kAVCUnitPowerOpcode = 0xb2, 107 108 // Common Unit + Subunit 109 kAVCCommonOpenDescriptorOpcode = 0x08, 110 kAVCCommonReadDescriptorOpcode = 0x09, 111 kAVCCommonWriteDescriptorOpcode = 0x0A, 112 kAVCCommonSearchDescriptorOpcode = 0x0B, 113 kAVCCommonObjectNumberSelectOpcode = 0x0D, 114 kAVCCommonPowerOpcode = 0xB2, 115 kAVCCommonReserveOpcode = 0x01, 116 kAVCCommonPlugInfoOpcode = 0x02, 117 kAVCCommonVendorDependentOpcode = 0x00, 118 119 // Panel 120 kAVCPanelPassThrough = 0x7c, 121 } IEEE1394Opcode; 122 123 // AVC param 0 124 typedef enum 125 { 126 kAVCPowerStateOn = 0x70, 127 kAVCPowerStateOff = 0x60, 128 kAVCPowerStateQuery = 0x7f, 129 } IEEE1394UnitPowerParam0; 130 131 typedef enum 132 { 133 kAVCPanelKeySelect = 0x00, 134 kAVCPanelKeyUp = 0x01, 135 kAVCPanelKeyDown = 0x02, 136 kAVCPanelKeyLeft = 0x03, 137 kAVCPanelKeyRight = 0x04, 138 kAVCPanelKeyRightUp = 0x05, 139 kAVCPanelKeyRightDown = 0x06, 140 kAVCPanelKeyLeftUp = 0x07, 141 kAVCPanelKeyLeftDown = 0x08, 142 kAVCPanelKeyRootMenu = 0x09, 143 kAVCPanelKeySetupMenu = 0x0A, 144 kAVCPanelKeyContentsMenu = 0x0B, 145 kAVCPanelKeyFavoriteMenu = 0x0C, 146 kAVCPanelKeyExit = 0x0D, 147 148 kAVCPanelKey0 = 0x20, 149 kAVCPanelKey1 = 0x21, 150 kAVCPanelKey2 = 0x22, 151 kAVCPanelKey3 = 0x23, 152 kAVCPanelKey4 = 0x24, 153 kAVCPanelKey5 = 0x25, 154 kAVCPanelKey6 = 0x26, 155 kAVCPanelKey7 = 0x27, 156 kAVCPanelKey8 = 0x28, 157 kAVCPanelKey9 = 0x29, 158 kAVCPanelKeyDot = 0x2A, 159 kAVCPanelKeyEnter = 0x2B, 160 kAVCPanelKeyClear = 0x2C, 161 162 kAVCPanelKeyChannelUp = 0x30, 163 kAVCPanelKeyChannelDown = 0x31, 164 kAVCPanelKeyPreviousChannel = 0x32, 165 kAVCPanelKeySoundSelect = 0x33, 166 kAVCPanelKeyInputSelect = 0x34, 167 kAVCPanelKeyDisplayInfo = 0x35, 168 kAVCPanelKeyHelp = 0x36, 169 kAVCPanelKeyPageUp = 0x37, 170 kAVCPanelKeyPageDown = 0x38, 171 172 kAVCPanelKeyPower = 0x40, 173 kAVCPanelKeyVolumeUp = 0x41, 174 kAVCPanelKeyVolumeDown = 0x42, 175 kAVCPanelKeyMute = 0x43, 176 kAVCPanelKeyPlay = 0x44, 177 kAVCPanelKeyStop = 0x45, 178 kAVCPanelKeyPause = 0x46, 179 kAVCPanelKeyRecord = 0x47, 180 kAVCPanelKeyRewind = 0x48, 181 kAVCPanelKeyFastForward = 0x49, 182 kAVCPanelKeyEject = 0x4a, 183 kAVCPanelKeyForward = 0x4b, 184 kAVCPanelKeyBackward = 0x4c, 185 186 kAVCPanelKeyAngle = 0x50, 187 kAVCPanelKeySubPicture = 0x51, 188 189 kAVCPanelKeyTuneFunction = 0x67, 190 191 kAVCPanelKeyPress = 0x00, 192 kAVCPanelKeyRelease = 0x80, 193 194 } IEEE1394PanelPassThroughParam0; 195 196 R5000Device(uint64_t guid, uint subunitid, uint speed); 197 ~R5000Device(); 198 199 bool OpenPort(void); 200 bool ClosePort(void); 201 void RunPortHandler(void); 202 203 // Commands 204 virtual bool ResetBus(void) { return false; } 205 206 virtual void AddListener(TSDataListener*); 207 virtual void RemoveListener(TSDataListener*); 208 209 // Sets 210 virtual bool SetPowerState(bool on); 211 virtual bool SetChannel(const QString &panel_model, 212 uint alt_method, uint channel); 213 214 // Gets 215 bool IsSTBBufferCleared(void) const { return m_buffer_cleared; } 216 217 // non-const Gets 218 virtual PowerState GetPowerState(void); 219 220 // Statics 221 static bool IsSTBSupported(const QString &model); 222 static QString GetModelName(uint vendorid, uint modelid); 223 void BroadcastToListeners( 224 const unsigned char *data, uint dataSize); 225 226 protected: 227 228 bool GetSubunitInfo(uint8_t table[32]); 229 230 void SetLastChannel(uint channel); 231 void ProcessPATPacket(const TSPacket&); 232 bool StartStreaming(void); 233 bool StopStreaming(void); 234 235 uint64_t m_guid; 236 uint m_subunitid; 237 uint m_speed; 238 uint m_last_channel; 239 uint m_last_crc; 240 bool m_buffer_cleared; 241 242 uint m_open_port_cnt; 243 vector<TSDataListener*> m_listeners; 244 mutable QMutex m_lock; 245 246 /// Vendor ID + Model ID to R5000Device STB model string 247 static QMap<uint64_t,QString> s_id_to_model; 248 static QMutex s_static_lock; 249 private: 250 r5kdev_t *usbdev; 251 R5kPriv *m_priv; 252 }; 253 254 #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 MAX_URBS_IN_FLIGHT 128 19 #define R5K_URB_BUFFER_SIZE (1 << 14) 20 #define R5K_MAX_PIDS 10 21 22 typedef struct { 23 usb_dev_handle *handle; 24 struct usbdevfs_urb *urbs; 25 unsigned char *buffer; 26 unsigned char leftover[188]; 27 unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data); 28 void *cb_data; 29 int nexturb; 30 int streaming; 31 int offset; 32 int realtime; 33 int bytes_read; 34 #ifdef R5K_DEBUG 35 int fd; 36 #endif 37 unsigned char pmt_pkt[188]; 38 unsigned char num_pmt_entries; 39 unsigned char pmt_state; 40 unsigned char pmt_next_cc; 41 struct { 42 int pid; 43 unsigned char id; 44 } pmt[R5K_MAX_PIDS]; 45 } r5kdev_t; 46 47 static r5kdev_t *glbl_r5kdev; 48 static int r5000_usb_init = 0; 49 static unsigned char r5000_pat_pkt[188] = { 50 0x47, 0x40, 0x00, 0x13, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x06, 0xc5, 0x00, 0x00, 0x00, 0x01, 0xe0, 51 0x21, 0x19, 0x3a, 0x82, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 52 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 53 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 54 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55 0xff, 0xff, 0xff, 0xff, 0xff, 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}; 62 enum { 63 R5K_PMT_START = 0x01, 64 R5K_PMT_READY = 0x02 65 }; 66 static int r5000_pmt_state = 0; 67 static unsigned char r5000_pmt[188]; 68 static int r5000_pmt_count = 0; 69 static unsigned char r5000_pmt_partial[188*20]; 70 static int r5000_pmt_partial_count = 0; 71 static int r5000_pmt_cc; 72 static void r5000_process_urb(struct usbdevfs_urb *urb); 73 74 int r5000_create_urbs(r5kdev_t *r5kdev) 75 { 76 int i; 77 r5kdev->urbs = (struct usbdevfs_urb *)malloc(sizeof(struct usbdevfs_urb) * MAX_URBS_IN_FLIGHT); 78 r5kdev->buffer = malloc(R5K_URB_BUFFER_SIZE * MAX_URBS_IN_FLIGHT); 79 for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) { 80 usb_bulk_setup(&r5kdev->urbs[i], 0x82, r5kdev->buffer + (R5K_URB_BUFFER_SIZE*i), R5K_URB_BUFFER_SIZE); 81 } 82 r5kdev->nexturb = 0; 83 return 0; 84 } 85 86 int r5000_free_urbs(r5kdev_t *r5kdev) 87 { 88 free(r5kdev->urbs); 89 free(r5kdev->buffer); 90 return 0; 91 } 92 93 usb_dev_handle *r5000_locate_device( 94 unsigned short vendor_id, unsigned short product_id) 95 { 96 struct usb_bus *bus; 97 struct usb_device *dev; 98 usb_dev_handle *device_handle = 0; 99 usb_find_busses(); 100 usb_find_devices(); 101 102 for (bus = usb_get_busses(); bus; bus = bus->next) 103 { 104 for (dev = bus->devices; dev; dev = dev->next) 105 { 106 if (dev->descriptor.idVendor == vendor_id && 107 dev->descriptor.idProduct == product_id) 108 { 109 device_handle = usb_open(dev); 110 printf("XSV Device Found @ Address %s \n", dev->filename); 111 printf("XSV Vendor ID 0x0%x\n",dev->descriptor.idVendor); 112 printf("XSV Product ID 0x0%x\n",dev->descriptor.idProduct); 113 } 114 } 115 } 116 117 if (device_handle==0) return (0); 118 int open_status = usb_set_configuration(device_handle,1); 119 printf("conf_stat=%d\n",open_status); 120 121 open_status = usb_claim_interface(device_handle,0); 122 printf("claim_stat=%d\n",open_status); 123 124 open_status = usb_set_altinterface(device_handle,0); 125 printf("alt_stat=%d\n",open_status); 126 return (device_handle); 127 } 128 129 int r5000_start_stream(r5kdev_t *r5kdev) 130 { 131 unsigned char data[0x80]; 132 int bytes; 133 int i; 134 struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 135 136 if(! r5kdev->urbs) 137 r5000_create_urbs(r5kdev); 138 /* 139 data[0] = 0x20; 140 usb_bulk_write(handle, 1, data, 1, 5000); 141 142 bytes = usb_bulk_read(handle, 129, data, 4, 5000); 143 bytes = usb_bulk_read(handle, 129, data, 128, 5000); 144 */ 145 data[0] = 0x30; 146 usb_bulk_write(handle, 1, data, 1, 5000); 147 bytes = usb_bulk_read(handle, 129, data, 2, 5000); 148 149 data[0] = 0x50; 150 usb_bulk_write(handle, 1, data, 1, 5000); 151 152 for(i=0; i < MAX_URBS_IN_FLIGHT; i++) { 153 usb_urb_submit(handle, &r5kdev->urbs[i], NULL); 154 } 155 r5kdev->nexturb = 0; 156 r5kdev->streaming = 1; 157 r5kdev->offset = 0; 158 return 1; 159 } 160 161 int r5000_stop_stream(r5kdev_t *r5kdev) 162 { 163 struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 164 struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs; 165 int i; 166 167 if(r5kdev->streaming) { 168 for(i=0; i < MAX_URBS_IN_FLIGHT; i++) 169 usb_urb_cancel(handle, &urbs[i]); 170 r5kdev->streaming = 0; 171 } 172 return 0; 173 } 174 175 r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, int realtime) 176 { 177 r5kdev_t *r5kdev; 178 struct usb_dev_handle *handle; 179 if(! r5000_usb_init) { 180 usb_init(); 181 r5000_usb_init = 1; 182 } 183 handle = r5000_locate_device(0x0547, 0x1002); 184 if(! handle) 185 return NULL; 186 if(realtime) 187 usbdevfs_urb_signal_completion(r5000_process_urb); 188 r5kdev = (r5kdev_t *)calloc(1, sizeof(r5kdev_t)); 189 r5kdev->handle = handle; 190 r5kdev->urbs = NULL; 191 r5kdev->cb = cb; 192 r5kdev->cb_data = cb_data; 193 //r5kdev->realtime = realtime; 194 #ifdef R5K_DEBUG 195 r5kdev->fd = open("r5kdebug.raw", O_WRONLY | O_TRUNC | O_CREAT, 0666); 196 #endif 197 glbl_r5kdev = r5kdev; 198 return r5kdev; 199 } 200 201 int r5000_close(r5kdev_t *r5kdev) 202 { 203 if(! r5kdev) 204 return 0; 205 if(r5kdev->urbs) { 206 if(r5kdev->streaming) 207 r5000_stop_stream(r5kdev); 208 r5000_free_urbs(r5kdev); 209 } 210 #ifdef R5K_DEBUG 211 if(r5kdev->fd >= 0) 212 close(r5kdev->fd); 213 #endif 214 usb_close(r5kdev->handle); 215 free(r5kdev); 216 return 0; 217 } 218 #if 0 219 void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf) 220 { 221 int pid = ((buf[1] << 8) | buf[2]) & 0x1fff; 222 if(pid == 0x00 && r5000_pmt_state & R5K_PMT_READY) { 223 int i; 224 for(i = 0; i < r5000_pmt_count; i++) { 225 unsigned char *ptr = r5000_pmt + 188*i; 226 r5000_pmt_cc = (r5000_pmt_cc +1) &0xf; 227 ptr[3] = (ptr[3] & 0xf0) | r5000_pmt_cc; 228 r5kdev->cb(ptr, 188, r5kdev->cb_data); 229 } 230 } else if(pid == 0x21) { 231 r5000_pmt_cc = buf[3] & 0xf; 232 if(buf[1] & 0x40 && buf[4] == 0x00 && buf[5] == 0x02) { 233 if(r5000_pmt_state & R5K_PMT_START) { 234 memcpy(r5000_pmt, r5000_pmt_partial, 188 * r5000_pmt_partial_count); 235 r5000_pmt_count = r5000_pmt_partial_count; 236 r5000_pmt_state |= R5K_PMT_READY; 237 } 238 memcpy(r5000_pmt_partial, buf, 188); 239 r5000_pmt_partial_count = 1; 240 r5000_pmt_state |= R5K_PMT_START; 241 } else if(r5000_pmt_state & R5K_PMT_START) { 242 memcpy(r5000_pmt_partial + 188*r5000_pmt_partial_count, buf, 188); 243 r5000_pmt_partial_count++; 244 } 245 } 246 } 247 #else 248 //taken and adapted from libdtv, (c) Rolf Hakenes 249 // CRC32 lookup table for polynomial 0x04c11db7 250 static unsigned int crc_table[256] = { 251 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 252 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 253 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 254 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 255 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 256 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 257 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 258 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 259 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 260 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 261 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 262 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 263 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 264 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 265 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 266 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 267 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 268 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 269 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 270 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 271 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 272 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 273 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 274 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 275 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 276 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 277 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 278 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 279 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 280 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 281 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 282 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 283 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 284 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 285 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 286 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 287 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 288 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 289 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 290 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 291 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 292 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 293 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; 294 295 void r5000_calc_crc(unsigned char *out, const unsigned char *d, int len) 296 { 297 register int i; 298 unsigned int crc = 0xFFFFFFFF; 299 const unsigned char *u=(unsigned char*)d; // Saves '& 0xff' 300 301 for (i=0; i<len; i++) 302 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)]; 303 304 *out++ = (crc >> 24) & 0xff; 305 *out++ = (crc >> 16) & 0xff; 306 *out++ = (crc >> 8) & 0xff; 307 *out++ = (crc >> 0) & 0xff; 308 } 309 310 #define IS_VIDEO(x) ((x) == 0x02 || (x) == 0x1b) 311 void r5000_send_pmt(r5kdev_t *r5kdev) 312 { 313 if(r5kdev->pmt_pkt[0] != 0x47) { 314 int len; 315 int i; 316 unsigned char *ptr; 317 unsigned char ts[188] = { 318 0x47, 0x40, 0x21, 0x10, 319 0x00, 0x02, 320 0xb0, 0x00, //length 321 0x00, 0x01, 322 0xc3, 0x00, 0x00, 323 0xf0, 0x00, //PCR_PID 324 0xf0, 0x00}; //Program Info Length 325 ts[3] = 0x10 | r5kdev->pmt_next_cc; 326 printf("Building PMT\n"); 327 ptr = ts + 17; 328 for(i = 0; i < r5kdev->num_pmt_entries; i++) { 329 *ptr++ = r5kdev->pmt[i].id; 330 *ptr++ = 0xe0 | (r5kdev->pmt[i].pid>>8); 331 *ptr++ = r5kdev->pmt[i].pid & 0xff; 332 *ptr++ = 0xf0; 333 if(IS_VIDEO(r5kdev->pmt[i].id)) { 334 *ptr++ = 0x00; 335 ts[13] = 0xe0 | (r5kdev->pmt[i].pid >> 8); 336 ts[14] = r5kdev->pmt[i].pid & 0xff; 337 } else { 338 *ptr++ = 0x06; 339 *ptr++ = 0x0a; 340 *ptr++ = 0x04; 341 *ptr++ = 0x65; 342 *ptr++ = 0x6e; 343 *ptr++ = 0x67; 344 *ptr++ = 0x00; 345 } 346 } 347 ts[7] = (ptr - ts) - 8/*header*/ + 4/*CRC*/; 348 r5000_calc_crc(ptr, ts + 5, (ptr - ts) - 5); 349 memset(ptr+4, 0xff, 188 - (ptr - ts - 4)); 350 memcpy(r5kdev->pmt_pkt, ts, 188); 351 } 352 r5kdev->pmt_pkt[3] = 0x10 | r5kdev->pmt_next_cc; 353 r5kdev->pmt_next_cc = (r5kdev->pmt_next_cc + 1) & 0x0f; 354 r5kdev->cb(r5kdev->pmt_pkt, 188, r5kdev->cb_data); 355 } 356 357 void r5000_add_pmt(r5kdev_t *r5kdev, int pid, int table_id) 358 { 359 int i; 360 int is_video = IS_VIDEO(table_id); 361 362 for(i = 0; i < r5kdev->num_pmt_entries; i++) { 363 if(r5kdev->pmt[i].pid == pid) { 364 if(r5kdev->pmt[i].id == table_id) 365 return; 366 //different table_id for existing pid. Reset 367 r5kdev->num_pmt_entries = 0; 368 r5kdev->pmt_state = 0; 369 r5kdev->pmt_pkt[0] = 0; 370 break; 371 } 372 if(is_video) { 373 if(IS_VIDEO(r5kdev->pmt[i].id)) { 374 //a video entry already exists. Reset 375 r5kdev->num_pmt_entries = 0; 376 r5kdev->pmt_state = 0; 377 r5kdev->pmt_pkt[0] = 0; 378 break; 379 } 380 } 381 } 382 //Didn't find this PID, add it 383 if(i == R5K_MAX_PIDS) 384 return; 385 printf("Adding %04x: %02x @ %08x\n", pid, table_id, r5kdev->bytes_read); 386 r5kdev->pmt[r5kdev->num_pmt_entries].pid = pid; 387 r5kdev->pmt[r5kdev->num_pmt_entries].id = table_id; 388 r5kdev->num_pmt_entries++; 389 r5kdev->pmt_state |= is_video ? 0x01 : 0x02; 390 } 391 392 void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf) 393 { 394 int stream_id, pid, afc, af_size = 0; 395 pid = ((buf[1] << 8) | buf[2]) & 0x1fff; 396 if(pid == 0x1fff) 397 return; 398 if(pid == 0) { 399 r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data); 400 if(r5kdev->pmt_state == 0x03) 401 r5000_send_pmt(r5kdev); 402 } else { 403 if(pid != 0x21) 404 r5kdev->cb(buf, 188, r5kdev->cb_data); 405 //Only interested in PES packets starting in this TS packet 406 if (!buf[1] & 0x40) 407 return; 408 afc = (buf[3]>>4) & 0x03; 409 if(afc == 0x2) 410 return; 411 if(afc == 0x3) 412 af_size = buf[4]+1; 413 if(buf[4+af_size] != 0x00 || buf[5+af_size] != 0x00 || buf[6+af_size] != 0x01) 414 return; 415 //We have a PES packet 416 stream_id = buf[7+af_size]; 417 if((stream_id & 0xf0) == 0xe0) { 418 //Video stream (we need the adaptation field) 419 if(afc != 0x03) 420 return; 421 if(0) { 422 int i; 423 for(i = 0; i < af_size+8; i++) { 424 printf("%02x ", buf[i]); 425 if((i %16) == 15) 426 printf("\n"); 427 } 428 printf("\n"); 429 } 430 if(buf[5] & 0x02) { 431 // Has private data, this is MPEG4 432 r5000_add_pmt(r5kdev, pid, 0x1b); 433 } else if(buf[5] & 0x10) { 434 // Has PCR and no private data, this is MPEG2 435 r5000_add_pmt(r5kdev, pid, 0x02); 436 } 437 } else if((stream_id & 0xf0) == 0xc0) { 438 //Audio stream 439 r5000_add_pmt(r5kdev, pid, 0x04); 440 } else if(stream_id == 0xbd) { 441 //Audio stream 442 r5000_add_pmt(r5kdev, pid, 0x81); 443 } 444 } 445 } 446 #endif 447 void r5000_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len) 448 { 449 int pos; 450 int sync = 1; 451 if(! r5kdev->streaming) 452 return; 453 if(len <= 0) 454 return; 455 456 pos = r5kdev->offset; 457 #ifdef R5K_DEBUG 458 if(r5kdev->fd >= 0) 459 write(r5kdev->fd, buf, len); 460 #endif 461 while(pos < len) { 462 if(buf[pos] != 0x47 || (pos <len-1 && buf[pos+1] == 0xff)) 463 goto nosync; 464 // If we get here, buf[pos] == 0x47 465 if(r5kdev->offset) { 466 //previous data exists and is part of a good packet 467 memcpy(r5kdev->leftover+188-r5kdev->offset, buf, r5kdev->offset); 468 r5000_force_pmt(r5kdev, r5kdev->leftover); 469 r5kdev->offset = 0; 470 } 471 if(pos+188 < len) { 472 //at least one full packet is available 473 if(buf[pos+188] != 0x47) 474 goto nosync; 475 } else { 476 //Out of data, but the partial packet may be ok. 477 memcpy(r5kdev->leftover, buf+pos, len-pos); 478 r5kdev->offset = 188-(len-pos); 479 break; 480 } 481 //If we get here, we have a good packet 482 r5000_force_pmt(r5kdev, buf+pos); 483 if(! sync) 484 printf("(%d) Found sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos); 485 sync = 1; 486 pos+=188; 487 continue; 488 nosync: 489 r5kdev->offset=0; 490 if(sync) 491 printf("(%d)Lost sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos); 492 sync = 0; 493 pos++; 494 } 495 r5kdev->bytes_read += len; 496 } 497 498 int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec) 499 { 500 struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 501 struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs; 502 int len; 503 unsigned char *buf; 504 struct timeval tv1, tv2; 505 if(! r5kdev->streaming) 506 return -1; 507 gettimeofday(&tv1, NULL); 508 len = usb_urb_reap(handle, &urbs[r5kdev->nexturb], timeout_usec); 509 gettimeofday(&tv2, NULL); 510 //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); 511 if(len <= 0) { 512 if(len != -ETIMEDOUT) 513 printf("(%d) Reap failed at %08x: %s\n", r5kdev->nexturb, r5kdev->bytes_read, strerror(errno)); 514 return len; 515 } 516 buf = r5kdev->buffer + (R5K_URB_BUFFER_SIZE*r5kdev->nexturb); 517 r5000_process_block(r5kdev, buf, len); 518 usb_urb_submit(handle, &urbs[r5kdev->nexturb], NULL); 519 r5kdev->nexturb = (r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT; 520 return 0; 521 } 522 523 static void r5000_process_urb(struct usbdevfs_urb *urb) 524 { 525 // struct timeval tv; 526 // gettimeofday(&tv, NULL); 527 // printf("Callback at %d.%06d: %d/%d\n", tv.tv_sec, tv.tv_usec, urb->buffer_length, urb->actual_length); 528 if(urb != &glbl_r5kdev->urbs[glbl_r5kdev->nexturb]) { 529 int i; 530 for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) { 531 if(urb == &glbl_r5kdev->urbs[i]) 532 break; 533 } 534 printf("Discontinuity: Expected %d but got %d!\n", glbl_r5kdev->nexturb, i); 535 } 536 r5000_process_block(glbl_r5kdev, urb->buffer, urb->actual_length); 537 usb_urb_submit(glbl_r5kdev->handle, urb, NULL); 538 glbl_r5kdev->nexturb = (glbl_r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT; 539 } 540 541 int r5000_read_status(r5kdev_t *r5kdev, unsigned char *buf) 542 { 543 return usb_bulk_read(r5kdev->handle, 129, buf, 128, 5000); 544 } 545 546 int r5000_get_power_state(r5kdev_t *r5kdev) 547 { 548 unsigned char data1[1] = { 0x30 }; 549 unsigned char data2[0x80]; 550 while(1) { 551 r5000_read_status(r5kdev, data2); 552 usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000); 553 usleep(100000); 554 if(usb_bulk_read(r5kdev->handle, 1, data2, 2, 5000) == 2 && 555 data2[0] == 0x0a || (data2[1] & 0x4e) == 0x4c) 556 return !!(data2[1] == 0x4d); 557 usleep(100000); 558 } 559 } 560 561 int r5000_toggle_on_off(r5kdev_t *r5kdev) 562 { 563 unsigned char data1[1] = { 0x30 }; 564 unsigned char data3[0x80], on_off; 565 int len; 566 on_off = r5000_get_power_state(r5kdev); 567 //printf("Start state: %s\n", on_off ? "On" : "Off"); 568 usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000); 569 usleep(100000); 570 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_POWER], 0x40, 5000); 571 usleep(100000); 572 len = usb_bulk_read(r5kdev->handle, 1, data3, 2, 5000); 573 usleep(100000); 574 while(r5000_get_power_state(r5kdev) == on_off) 575 usleep(100000); 576 //printf("End state: %s\n", !on_off ? "On" : "Off"); 577 return !on_off; 578 } 579 580 void r5000_change_channel(r5kdev_t *r5kdev, int chan) 581 { 582 int pos = 1000000, digit; 583 unsigned char data2[0x80]; 584 r5000_read_status(r5kdev, data2); 585 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_CLEAR], 0x40, 5000); 586 usleep(R5000_BUTTON_DELAY); 587 while(pos != 0 && (chan/pos) == 0) 588 pos /= 10; 589 if(pos == 0) 590 pos = 1; 591 while(pos != 0) { 592 digit = chan / pos; 593 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[digit], 0x40, 5000); 594 chan -= digit*pos; 595 pos/= 10; 596 usleep(R5000_BUTTON_DELAY); 597 } 598 usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_ENTER], 0x40, 5000); 599 } -
new file libs/libmythtv/r5000/r5000.h
- + 1 #ifndef R5000_H 2 #define R5000_H 3 4 #define r5kdev_t void 5 6 extern r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, int realtime); 7 extern int r5000_close(r5kdev_t *r5kdev); 8 extern int r5000_start_stream(r5kdev_t *r5kdev); 9 extern int r5000_stop_stream(r5kdev_t *r5kdev); 10 extern int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec); 11 extern int r5000_get_power_state(r5kdev_t *r5kdev); 12 extern int r5000_toggle_on_off(r5kdev_t *r5kdev); 13 extern void r5000_change_channel(r5kdev_t *r5kdev, int chan); 14 #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 };
