00001
00010
00011 #include <pthread.h>
00012 #include <sys/select.h>
00013 #include <unistd.h>
00014 #include <fcntl.h>
00015
00016
00017 #include <libraw1394/raw1394.h>
00018 #include <libraw1394/csr.h>
00019 #include <libiec61883/iec61883.h>
00020 #include <libavc1394/avc1394.h>
00021 #include <libavc1394/rom1394.h>
00022
00023 #include <netinet/in.h>
00024
00025
00026 #include <algorithm>
00027 using namespace std;
00028
00029
00030 #include <qdatetime.h>
00031
00032
00033 #include "linuxfirewiredevice.h"
00034 #include "firewirerecorder.h"
00035 #include "mythcontext.h"
00036 #include "linuxavcinfo.h"
00037
00038 #define LOC QString("LFireDev(%1): ").arg(guid_to_string(m_guid))
00039 #define LOC_WARN QString("LFireDev(%1), Warning: ").arg(guid_to_string(m_guid))
00040 #define LOC_ERR QString("LFireDev(%1), Error: ").arg(guid_to_string(m_guid))
00041
00042 #define kNoDataTimeout 50
00043 #define kResetTimeout 1000
00044
00045 typedef QMap<raw1394handle_t,LinuxFirewireDevice*> handle_to_lfd_t;
00046
00047 class LFDPriv
00048 {
00049 public:
00050 LFDPriv() :
00051 generation(0), reset_timer_on(false),
00052 run_port_handler(false), is_port_handler_running(false),
00053 avstream(NULL), channel(-1),
00054 output_plug(-1), input_plug(-1), bandwidth(0), no_data_cnt(0),
00055 is_p2p_node_open(false), is_bcast_node_open(false),
00056 is_streaming(false)
00057 {
00058 }
00059
00060 ~LFDPriv()
00061 {
00062 avcinfo_list_t::iterator it = devices.begin();
00063 for (; it != devices.end(); ++it)
00064 delete (*it);
00065 devices.clear();
00066 }
00067
00068 uint generation;
00069 bool reset_timer_on;
00070 MythTimer reset_timer;
00071
00072 bool run_port_handler;
00073 bool is_port_handler_running;
00074 QMutex start_stop_port_handler_lock;
00075
00076 iec61883_mpeg2_t avstream;
00077 int channel;
00078 int output_plug;
00079 int input_plug;
00080 int bandwidth;
00081 uint no_data_cnt;
00082
00083 bool is_p2p_node_open;
00084 bool is_bcast_node_open;
00085 bool is_streaming;
00086
00087 QDateTime stop_streaming_timer;
00088 pthread_t port_handler_thread;
00089
00090 avcinfo_list_t devices;
00091
00092 static QMutex s_lock;
00093 static handle_to_lfd_t s_handle_info;
00094 };
00095 QMutex LFDPriv::s_lock;
00096 handle_to_lfd_t LFDPriv::s_handle_info;
00097
00098 static void add_handle(raw1394handle_t handle, LinuxFirewireDevice *dev)
00099 {
00100 QMutexLocker slocker(&LFDPriv::s_lock);
00101 LFDPriv::s_handle_info[handle] = dev;
00102 }
00103
00104 static void remove_handle(raw1394handle_t handle)
00105 {
00106 QMutexLocker slocker(&LFDPriv::s_lock);
00107 LFDPriv::s_handle_info.erase(handle);
00108 }
00109
00110 const uint LinuxFirewireDevice::kBroadcastChannel = 63;
00111 const uint LinuxFirewireDevice::kConnectionP2P = 0;
00112 const uint LinuxFirewireDevice::kConnectionBroadcast = 1;
00113 const uint LinuxFirewireDevice::kMaxBufferedPackets = 2000;
00114
00115
00116 int linux_firewire_device_tspacket_handler(
00117 unsigned char *tspacket, int len, uint dropped, void *callback_data);
00118 void *linux_firewire_device_port_handler_thunk(void *param);
00119 static bool has_data(int fd, uint msec);
00120 static QString speed_to_string(uint speed);
00121 static int linux_firewire_device_bus_reset_handler(
00122 raw1394handle_t handle, uint generation);
00123 static bool get_guid(raw1394handle_t handle, nodeid_t node,
00124 uint64_t &guid, bool &temp_unavailable);
00125
00126 LinuxFirewireDevice::LinuxFirewireDevice(
00127 uint64_t guid, uint subunitid,
00128 uint speed, bool use_p2p, uint av_buffer_size_in_bytes) :
00129 FirewireDevice(guid, subunitid, speed),
00130 m_bufsz(av_buffer_size_in_bytes),
00131 m_db_reset_disabled(false),
00132 m_use_p2p(use_p2p), m_priv(new LFDPriv())
00133 {
00134 if (!m_bufsz)
00135 m_bufsz = gContext->GetNumSetting("HDRingbufferSize");
00136
00137 m_db_reset_disabled = gContext->GetNumSetting("DisableFirewireReset", 0);
00138
00139 UpdateDeviceList();
00140 }
00141
00142 LinuxFirewireDevice::~LinuxFirewireDevice()
00143 {
00144 if (IsPortOpen())
00145 {
00146 VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port");
00147 while (IsPortOpen())
00148 ClosePort();
00149 }
00150
00151 if (m_priv)
00152 {
00153 delete m_priv;
00154 m_priv = NULL;
00155 }
00156 }
00157
00158 void LinuxFirewireDevice::SignalReset(uint generation)
00159 {
00160 const QString loc = LOC + QString("SignalReset(%1->%2)")
00161 .arg(m_priv->generation).arg(generation);
00162
00163 VERBOSE(VB_IMPORTANT, loc);
00164
00165 if (GetInfoPtr())
00166 raw1394_update_generation(GetInfoPtr()->fw_handle, generation);
00167
00168 m_priv->generation = generation;
00169
00170 VERBOSE(VB_IMPORTANT, loc + ": Updating device list -- begin");
00171 UpdateDeviceList();
00172 VERBOSE(VB_IMPORTANT, loc + ": Updating device list -- end");
00173
00174 m_priv->reset_timer_on = true;
00175 m_priv->reset_timer.start();
00176 }
00177
00178 void LinuxFirewireDevice::HandleBusReset(void)
00179 {
00180 const QString loc = LOC + "HandleBusReset";
00181
00182 if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
00183 return;
00184
00185 if (m_priv->is_p2p_node_open)
00186 {
00187 VERBOSE(VB_IMPORTANT, loc + ": Reconnecting P2P connection");
00188 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00189 nodeid_t input = raw1394_get_local_id(GetInfoPtr()->fw_handle);
00190
00191 int fwchan = iec61883_cmp_reconnect(
00192 GetInfoPtr()->fw_handle,
00193 output, &m_priv->output_plug,
00194 input, &m_priv->input_plug,
00195 &m_priv->bandwidth, m_priv->channel);
00196
00197 if (fwchan < 0)
00198 {
00199 VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset: Failed to reconnect");
00200 }
00201 else if (fwchan != m_priv->channel)
00202 {
00203 VERBOSE(VB_IMPORTANT, LOC_WARN + QString("FWChan changed %1->%2")
00204 .arg(m_priv->channel).arg(fwchan));
00205 }
00206 m_priv->channel = fwchan;
00207
00208 VERBOSE(VB_IMPORTANT,
00209 loc + ": Reconnected fwchan: "<<fwchan<<"\n\t\t\t"
00210 <<hex<<"output: 0x"<<output<<" input: 0x"<<input<<dec);
00211 }
00212
00213 if (m_priv->is_bcast_node_open)
00214 {
00215 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00216
00217 VERBOSE(VB_RECORD, loc + ": Restarting broadcast connection on " +
00218 QString("node %1, channel %2")
00219 .arg(GetInfoPtr()->GetNode()).arg(m_priv->channel));
00220
00221 int err = iec61883_cmp_create_bcast_output(
00222 GetInfoPtr()->fw_handle,
00223 output, m_priv->output_plug,
00224 m_priv->channel, m_speed);
00225
00226 if (err < 0)
00227 {
00228 VERBOSE(VB_IMPORTANT, LOC_ERR +
00229 "Bus Reset : Failed to reconnect");
00230 }
00231 }
00232 }
00233
00234 bool LinuxFirewireDevice::OpenPort(void)
00235 {
00236 VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread");
00237 QMutexLocker locker(&m_priv->start_stop_port_handler_lock);
00238 VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread -- locked");
00239
00240 VERBOSE(VB_RECORD, LOC + "OpenPort()");
00241
00242 QMutexLocker mlocker(&m_lock);
00243
00244 VERBOSE(VB_RECORD, LOC + "OpenPort() -- got lock");
00245
00246 if (!GetInfoPtr())
00247 return false;
00248
00249 if (GetInfoPtr()->IsPortOpen())
00250 {
00251 m_open_port_cnt++;
00252 return true;
00253 }
00254
00255 if (!GetInfoPtr()->OpenPort())
00256 return false;
00257
00258 add_handle(GetInfoPtr()->fw_handle, this);
00259
00260 m_priv->generation = raw1394_get_generation(GetInfoPtr()->fw_handle);
00261 raw1394_set_bus_reset_handler(
00262 GetInfoPtr()->fw_handle, linux_firewire_device_bus_reset_handler);
00263
00264 GetInfoPtr()->GetSubunitInfo();
00265 VERBOSE(VB_RECORD, LOC + GetInfoPtr()->GetSubunitInfoString());
00266
00267 if (!GetInfoPtr()->IsSubunitType(kAVCSubunitTypeTuner) ||
00268 !GetInfoPtr()->IsSubunitType(kAVCSubunitTypePanel))
00269 {
00270 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Not an STB"));
00271
00272 m_lock.unlock();
00273 ClosePort();
00274 m_lock.lock();
00275
00276 return false;
00277 }
00278
00279 VERBOSE(VB_RECORD, LOC + "Starting port handler thread");
00280 m_priv->run_port_handler = true;
00281 pthread_create(&m_priv->port_handler_thread, NULL,
00282 linux_firewire_device_port_handler_thunk, this);
00283
00284 VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to start");
00285 while (!m_priv->is_port_handler_running)
00286 {
00287 m_lock.unlock();
00288 usleep(5000);
00289 m_lock.lock();
00290 }
00291
00292 VERBOSE(VB_RECORD, LOC + "Port handler thread started");
00293
00294 m_open_port_cnt++;
00295
00296 return true;
00297 }
00298
00299 bool LinuxFirewireDevice::ClosePort(void)
00300 {
00301 VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread");
00302 QMutexLocker locker(&m_priv->start_stop_port_handler_lock);
00303 VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread -- locked");
00304
00305 QMutexLocker mlocker(&m_lock);
00306
00307 VERBOSE(VB_RECORD, LOC + "ClosePort()");
00308
00309 if (m_open_port_cnt < 1)
00310 return false;
00311
00312 m_open_port_cnt--;
00313
00314 if (m_open_port_cnt != 0)
00315 return true;
00316
00317 if (!GetInfoPtr())
00318 return false;
00319
00320 if (GetInfoPtr()->IsPortOpen())
00321 {
00322 if (IsNodeOpen())
00323 CloseNode();
00324
00325 VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to stop");
00326 m_priv->run_port_handler = false;
00327 while (m_priv->is_port_handler_running)
00328 {
00329 m_lock.unlock();
00330 usleep(5000);
00331 m_lock.lock();
00332 }
00333
00334 VERBOSE(VB_RECORD, LOC + "Joining port handler thread");
00335 pthread_join(m_priv->port_handler_thread, NULL);
00336
00337 remove_handle(GetInfoPtr()->fw_handle);
00338
00339 if (!GetInfoPtr()->ClosePort())
00340 return false;
00341 }
00342
00343 return true;
00344 }
00345
00346 void LinuxFirewireDevice::AddListener(TSDataListener *listener)
00347 {
00348 QMutexLocker locker(&m_lock);
00349
00350 FirewireDevice::AddListener(listener);
00351
00352 if (!m_listeners.empty())
00353 {
00354 OpenNode();
00355 OpenAVStream();
00356 StartStreaming();
00357 }
00358 }
00359
00360 void LinuxFirewireDevice::RemoveListener(TSDataListener *listener)
00361 {
00362 QMutexLocker locker(&m_lock);
00363
00364 FirewireDevice::RemoveListener(listener);
00365
00366 if (m_listeners.empty())
00367 {
00368 StopStreaming();
00369 CloseAVStream();
00370 CloseNode();
00371 }
00372 }
00373
00374 bool LinuxFirewireDevice::SendAVCCommand(
00375 const vector<uint8_t> &cmd,
00376 vector<uint8_t> &result,
00377 int retry_cnt)
00378 {
00379 return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
00380 }
00381
00382 bool LinuxFirewireDevice::IsPortOpen(void) const
00383 {
00384 QMutexLocker locker(&m_lock);
00385
00386 if (!GetInfoPtr())
00387 return false;
00388
00389 return GetInfoPtr()->IsPortOpen();
00390 }
00391
00393
00394
00395 bool LinuxFirewireDevice::OpenNode(void)
00396 {
00397 if (m_use_p2p)
00398 return OpenP2PNode();
00399 else
00400 return OpenBroadcastNode();
00401 }
00402
00403 bool LinuxFirewireDevice::CloseNode(void)
00404 {
00405 if (m_priv->is_p2p_node_open)
00406 return CloseP2PNode();
00407
00408 if (m_priv->is_bcast_node_open)
00409 return CloseBroadcastNode();
00410
00411 return true;
00412 }
00413
00414
00415
00416 bool LinuxFirewireDevice::OpenP2PNode(void)
00417 {
00418 if (m_priv->is_bcast_node_open)
00419 return false;
00420
00421 if (m_priv->is_p2p_node_open)
00422 return true;
00423
00424 VERBOSE(VB_RECORD, LOC + "Opening P2P connection");
00425
00426 m_priv->bandwidth = +1;
00427 m_priv->output_plug = -1;
00428 m_priv->input_plug = -1;
00429 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00430 nodeid_t input = raw1394_get_local_id(GetInfoPtr()->fw_handle);
00431 m_priv->channel = iec61883_cmp_connect(GetInfoPtr()->fw_handle,
00432 output, &m_priv->output_plug,
00433 input, &m_priv->input_plug,
00434 &m_priv->bandwidth);
00435
00436 if (m_priv->channel < 0)
00437 {
00438 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create P2P connection");
00439
00440 m_priv->bandwidth = 0;
00441
00442 return false;
00443 }
00444
00445 m_priv->is_p2p_node_open = true;
00446
00447 return true;
00448 }
00449
00450 bool LinuxFirewireDevice::CloseP2PNode(void)
00451 {
00452 if (m_priv->is_p2p_node_open && (m_priv->channel >= 0))
00453 {
00454 VERBOSE(VB_RECORD, LOC + "Closing P2P connection");
00455
00456 if (m_priv->avstream)
00457 CloseAVStream();
00458
00459 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00460 nodeid_t input = raw1394_get_local_id(GetInfoPtr()->fw_handle);
00461
00462 iec61883_cmp_disconnect(GetInfoPtr()->fw_handle,
00463 output, m_priv->output_plug,
00464 input, m_priv->input_plug,
00465 m_priv->channel, m_priv->bandwidth);
00466
00467 m_priv->channel = -1;
00468 m_priv->output_plug = -1;
00469 m_priv->input_plug = -1;
00470 m_priv->is_p2p_node_open = false;
00471 }
00472
00473 return true;
00474 }
00475
00476 bool LinuxFirewireDevice::OpenBroadcastNode(void)
00477 {
00478 if (m_priv->is_p2p_node_open)
00479 return false;
00480
00481 if (m_priv->is_bcast_node_open)
00482 return true;
00483
00484 if (m_priv->avstream)
00485 CloseAVStream();
00486
00487 m_priv->channel = kBroadcastChannel - GetInfoPtr()->GetNode();
00488 m_priv->output_plug = 0;
00489 m_priv->input_plug = 0;
00490 nodeid_t output = GetInfoPtr()->GetNode() | 0xffc0;
00491
00492 VERBOSE(VB_RECORD, LOC + "Opening broadcast connection on " +
00493 QString("node %1, channel %2")
00494 .arg(GetInfoPtr()->GetNode()).arg(m_priv->channel));
00495
00496 int err = iec61883_cmp_create_bcast_output(
00497 GetInfoPtr()->fw_handle,
00498 output, m_priv->output_plug,
00499 m_priv->channel, m_speed);
00500
00501 if (err != 0)
00502 {
00503 VERBOSE(VB_IMPORTANT, LOC_ERR +
00504 "Failed to create Broadcast connection");
00505
00506 m_priv->channel = -1;
00507 m_priv->output_plug = -1;
00508 m_priv->input_plug = -1;
00509
00510 return false;
00511 }
00512
00513 m_priv->is_bcast_node_open = true;
00514
00515 return true;
00516 }
00517
00518 bool LinuxFirewireDevice::CloseBroadcastNode(void)
00519 {
00520 if (m_priv->is_bcast_node_open)
00521 {
00522 VERBOSE(VB_RECORD, LOC + "Closing broadcast connection");
00523
00524 m_priv->channel = -1;
00525 m_priv->output_plug = -1;
00526 m_priv->input_plug = -1;
00527 m_priv->is_bcast_node_open = false;
00528 }
00529 return true;
00530 }
00531
00532 bool LinuxFirewireDevice::OpenAVStream(void)
00533 {
00534 VERBOSE(VB_RECORD, LOC + "OpenAVStream");
00535
00536 if (!GetInfoPtr() || !GetInfoPtr()->IsPortOpen())
00537 {
00538 VERBOSE(VB_IMPORTANT, LOC +
00539 "Can not open AVStream without open IEEE 1394 port");
00540
00541 return false;
00542 }
00543
00544 if (!IsNodeOpen() && !OpenNode())
00545 return false;
00546
00547 if (m_priv->avstream)
00548 return true;
00549
00550 VERBOSE(VB_RECORD, LOC + "Opening A/V stream object");
00551
00552 m_priv->avstream = iec61883_mpeg2_recv_init(
00553 GetInfoPtr()->fw_handle, linux_firewire_device_tspacket_handler, this);
00554
00555 if (!m_priv->avstream)
00556 {
00557 VERBOSE(VB_IMPORTANT, LOC + "Unable to open AVStream" + ENO);
00558
00559 return false;
00560 }
00561
00562 iec61883_mpeg2_set_synch(m_priv->avstream, 1 );
00563
00564 if (m_bufsz)
00565 SetAVStreamBufferSize(m_bufsz);
00566
00567 return true;
00568 }
00569
00570 bool LinuxFirewireDevice::CloseAVStream(void)
00571 {
00572 if (!m_priv->avstream)
00573 return true;
00574
00575 VERBOSE(VB_RECORD, LOC + "Closing A/V stream object");
00576
00577 while (m_listeners.size())
00578 FirewireDevice::RemoveListener(m_listeners[m_listeners.size() - 1]);
00579
00580 if (m_priv->is_streaming)
00581 StopStreaming();
00582
00583 iec61883_mpeg2_close(m_priv->avstream);
00584 m_priv->avstream = NULL;
00585
00586 return true;
00587 }
00588
00589 void *linux_firewire_device_port_handler_thunk(void *param)
00590 {
00591 LinuxFirewireDevice *mon = (LinuxFirewireDevice*) param;
00592 mon->RunPortHandler();
00593 return NULL;
00594 }
00595
00596 void LinuxFirewireDevice::RunPortHandler(void)
00597 {
00598 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start");
00599 m_lock.lock();
00600 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock");
00601 m_priv->is_port_handler_running = true;
00602
00603 m_priv->no_data_cnt = 0;
00604 while (m_priv->run_port_handler)
00605 {
00606 LFDPriv::s_lock.lock();
00607 bool reset_timer_on = m_priv->reset_timer_on;
00608 bool handle_reset = reset_timer_on &&
00609 (m_priv->reset_timer.elapsed() > 100);
00610 if (handle_reset)
00611 m_priv->reset_timer_on = false;
00612 LFDPriv::s_lock.unlock();
00613
00614 if (handle_reset)
00615 HandleBusReset();
00616
00617 if (!reset_timer_on && m_priv->is_streaming &&
00618 (m_priv->no_data_cnt > (kResetTimeout / kNoDataTimeout)))
00619 {
00620 m_priv->no_data_cnt = 0;
00621 ResetBus();
00622 }
00623
00624 int fwfd = raw1394_get_fd(GetInfoPtr()->fw_handle);
00625 if (fwfd < 0)
00626 {
00627
00628
00629 m_lock.unlock();
00630 usleep(kNoDataTimeout);
00631 m_lock.lock();
00632
00633 m_priv->no_data_cnt += (m_priv->is_streaming) ? 1 : 0;
00634 continue;
00635 }
00636
00637
00638
00639
00640
00641 m_lock.unlock();
00642 bool ready = has_data(fwfd, kNoDataTimeout);
00643 m_lock.lock();
00644
00645 if (!ready && m_priv->is_streaming)
00646 {
00647 m_priv->no_data_cnt++;
00648
00649 VERBOSE(VB_IMPORTANT, LOC_WARN + QString("No Input in %1 msec...")
00650 .arg(m_priv->no_data_cnt * kNoDataTimeout));
00651 }
00652
00653
00654 if (ready && has_data(fwfd, 1 ))
00655 {
00656
00657
00658
00659
00660
00661 int ret = raw1394_loop_iterate(GetInfoPtr()->fw_handle);
00662 if (-1 == ret)
00663 {
00664 VERBOSE(VB_IMPORTANT, LOC_ERR + "raw1394_loop_iterate" + ENO);
00665 }
00666 }
00667 }
00668
00669 m_priv->is_port_handler_running = false;
00670 m_lock.unlock();
00671 VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end");
00672 }
00673
00674 bool LinuxFirewireDevice::StartStreaming(void)
00675 {
00676 if (m_priv->is_streaming)
00677 return m_priv->is_streaming;
00678
00679 if (!IsAVStreamOpen() && !OpenAVStream())
00680 return false;
00681
00682 if (m_priv->channel < 0)
00683 {
00684 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming, no channel");
00685 return false;
00686 }
00687
00688 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- really");
00689
00690 if (iec61883_mpeg2_recv_start(m_priv->avstream, m_priv->channel) == 0)
00691 {
00692 m_priv->is_streaming = true;
00693 }
00694 else
00695 {
00696 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming " + ENO);
00697 }
00698
00699 VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- done");
00700
00701 return m_priv->is_streaming;
00702 }
00703
00704 bool LinuxFirewireDevice::StopStreaming(void)
00705 {
00706 if (m_priv->is_streaming)
00707 {
00708 VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really");
00709
00710 m_priv->is_streaming = false;
00711
00712 iec61883_mpeg2_recv_stop(m_priv->avstream);
00713
00714 raw1394_iso_recv_flush(GetInfoPtr()->fw_handle);
00715 }
00716
00717 VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming");
00718
00719 return true;
00720 }
00721
00722 bool LinuxFirewireDevice::SetAVStreamBufferSize(uint size_in_bytes)
00723 {
00724 if (!m_priv->avstream)
00725 return false;
00726
00727
00728 uint buffer_size = max(size_in_bytes, 50 * TSPacket::SIZE);
00729 size_t buffered_packets = min(buffer_size / 4, kMaxBufferedPackets);
00730
00731 iec61883_mpeg2_set_buffers(m_priv->avstream, buffered_packets);
00732
00733 VERBOSE(VB_IMPORTANT, LOC +
00734 QString("Buffered packets %1 (%2 KB)")
00735 .arg(buffered_packets).arg(buffered_packets * 4));
00736
00737 return true;
00738 }
00739
00740 bool LinuxFirewireDevice::SetAVStreamSpeed(uint speed)
00741 {
00742 if (!m_priv->avstream)
00743 return false;
00744
00745 uint curspeed = iec61883_mpeg2_get_speed(m_priv->avstream);
00746
00747 if (curspeed == speed)
00748 {
00749 m_speed = speed;
00750 return true;
00751 }
00752
00753 VERBOSE(VB_RECORD, LOC +
00754 QString("Changing Speed %1 -> %2")
00755 .arg(speed_to_string(curspeed))
00756 .arg(speed_to_string(m_speed)));
00757
00758 iec61883_mpeg2_set_speed(m_priv->avstream, speed);
00759
00760 if (speed == (uint)iec61883_mpeg2_get_speed(m_priv->avstream))
00761 {
00762 m_speed = speed;
00763 return true;
00764 }
00765
00766 VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set firewire speed.");
00767
00768 return false;
00769 }
00770
00771 bool LinuxFirewireDevice::IsNodeOpen(void) const
00772 {
00773 return m_priv->is_p2p_node_open || m_priv->is_bcast_node_open;
00774 }
00775
00776 bool LinuxFirewireDevice::IsAVStreamOpen(void) const
00777 {
00778 return m_priv->avstream;
00779 }
00780
00781 bool LinuxFirewireDevice::ResetBus(void)
00782 {
00783 VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- begin");
00784
00785 if (m_db_reset_disabled)
00786 {
00787 VERBOSE(VB_IMPORTANT, LOC_WARN + "Bus Reset disabled" + ENO);
00788 VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end");
00789 return true;
00790 }
00791
00792 bool ok = (raw1394_reset_bus_new(GetInfoPtr()->fw_handle,
00793 RAW1394_LONG_RESET) == 0);
00794 if (!ok)
00795 VERBOSE(VB_IMPORTANT, LOC_ERR + "Bus Reset failed" + ENO);
00796
00797 VERBOSE(VB_IMPORTANT, LOC + "ResetBus() -- end");
00798
00799 return ok;
00800 }
00801
00802 void LinuxFirewireDevice::PrintDropped(uint dropped_packets)
00803 {
00804 if (dropped_packets == 1)
00805 {
00806 VERBOSE(VB_RECORD, LOC_ERR + "Dropped a TS packet");
00807 }
00808 else if (dropped_packets > 1)
00809 {
00810 VERBOSE(VB_RECORD, LOC_ERR +
00811 QString("Dropped %1 TS packets").arg(dropped_packets));
00812 }
00813 }
00814
00815 vector<AVCInfo> LinuxFirewireDevice::GetSTBList(void)
00816 {
00817 vector<AVCInfo> list;
00818
00819 {
00820 LinuxFirewireDevice dev(0,0,0,false);
00821 list = dev.GetSTBListPrivate();
00822 }
00823
00824 return list;
00825 }
00826
00827 vector<AVCInfo> LinuxFirewireDevice::GetSTBListPrivate(void)
00828 {
00829 VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- begin");
00830 QMutexLocker locker(&m_lock);
00831 VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- got lock");
00832
00833 vector<AVCInfo> list;
00834
00835 avcinfo_list_t::iterator it = m_priv->devices.begin();
00836 for (; it != m_priv->devices.end(); ++it)
00837 {
00838 if ((*it)->IsSubunitType(kAVCSubunitTypeTuner) &&
00839 (*it)->IsSubunitType(kAVCSubunitTypePanel))
00840 {
00841 list.push_back(*(*it));
00842 }
00843 }
00844
00845 VERBOSE(VB_IMPORTANT, "GetSTBListPrivate -- end");
00846 return list;
00847 }
00848
00849 typedef struct
00850 {
00851 raw1394handle_t handle;
00852 int port;
00853 int node;
00854 } dev_item;
00855
00856 bool LinuxFirewireDevice::UpdateDeviceList(void)
00857 {
00858 dev_item item;
00859
00860 item.handle = raw1394_new_handle();
00861 if (!item.handle)
00862 {
00863 VERBOSE(VB_IMPORTANT, "Couldn't get handle" + ENO);
00864 return false;
00865 }
00866
00867 struct raw1394_portinfo port_info[16];
00868 int numcards = raw1394_get_port_info(item.handle, port_info, 16);
00869 if (numcards < 1)
00870 {
00871 raw1394_destroy_handle(item.handle);
00872 return true;
00873 }
00874
00875 map<uint64_t,bool> guid_online;
00876 for (int port = 0; port < numcards; port++)
00877 {
00878 if (raw1394_set_port(item.handle, port) < 0)
00879 {
00880 VERBOSE(VB_IMPORTANT, "Couldn't set port to " << port);
00881 continue;
00882 }
00883
00884 MythTimer guid_timer;
00885 guid_timer.start();
00886 for (int node = 0; node < raw1394_get_nodecount(item.handle); node++)
00887 {
00888 bool tmp;
00889 uint64_t guid;
00890 if (!get_guid(item.handle, 0xffc0 | node, guid, tmp))
00891 {
00892 if (tmp && (guid_timer.elapsed() < 200))
00893 {
00894 usleep(10 * 1000);
00895 node--;
00896 }
00897 continue;
00898 }
00899
00900 item.port = port;
00901 item.node = node;
00902 UpdateDeviceListItem(guid, &item);
00903 guid_online[guid] = true;
00904 guid_timer.start();
00905 }
00906
00907 raw1394_destroy_handle(item.handle);
00908
00909 item.handle = raw1394_new_handle();
00910 if (!item.handle)
00911 {
00912 VERBOSE(VB_IMPORTANT, "Couldn't get handle "
00913 "(after setting port "<<port<<")" + ENO);
00914 item.handle = NULL;
00915 break;
00916 }
00917
00918 numcards = raw1394_get_port_info(item.handle, port_info, 16);
00919 }
00920
00921 if (item.handle)
00922 {
00923 raw1394_destroy_handle(item.handle);
00924 item.handle = NULL;
00925 }
00926
00927 item.port = -1;
00928 item.node = -1;
00929 avcinfo_list_t::iterator it = m_priv->devices.begin();
00930 for (; it != m_priv->devices.end(); ++it)
00931 {
00932 if (!guid_online[it.key()])
00933 UpdateDeviceListItem(it.key(), &item);
00934 }
00935
00936 return true;
00937 }
00938
00939 void LinuxFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
00940 {
00941 avcinfo_list_t::iterator it = m_priv->devices.find(guid);
00942
00943 if (it == m_priv->devices.end())
00944 {
00945 LinuxAVCInfo *ptr = new LinuxAVCInfo();
00946
00947 VERBOSE(VB_RECORD, LOC + "Adding 0x"<<hex<<guid<<dec);
00948
00949 m_priv->devices[guid] = ptr;
00950 it = m_priv->devices.find(guid);
00951 }
00952
00953 if (it != m_priv->devices.end())
00954 {
00955 dev_item &item = *((dev_item*) pitem);
00956 VERBOSE(VB_RECORD, LOC + "Updating 0x"<<hex<<guid<<dec
00957 <<" port: "<<item.port<<" node: "<<item.node);
00958
00959 (*it)->Update(guid, item.handle, item.port, item.node);
00960 }
00961 }
00962
00963 LinuxAVCInfo *LinuxFirewireDevice::GetInfoPtr(void)
00964 {
00965 avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
00966 return (it == m_priv->devices.end()) ? NULL : *it;
00967 }
00968
00969 const LinuxAVCInfo *LinuxFirewireDevice::GetInfoPtr(void) const
00970 {
00971 avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
00972 return (it == m_priv->devices.end()) ? NULL : *it;
00973 }
00974
00975 int linux_firewire_device_tspacket_handler(
00976 unsigned char *tspacket, int len, uint dropped, void *callback_data)
00977 {
00978 LinuxFirewireDevice *fw = (LinuxFirewireDevice*) callback_data;
00979 if (!fw)
00980 return 0;
00981
00982 if (dropped)
00983 fw->PrintDropped(dropped);
00984
00985 if (len > 0)
00986 fw->BroadcastToListeners(tspacket, len);
00987
00988 return 1;
00989 }
00990
00991 static bool has_data(int fd, uint msec)
00992 {
00993 fd_set rfds;
00994 FD_ZERO(&rfds);
00995 FD_SET(fd, &rfds);
00996
00997 struct timeval tv;
00998 tv.tv_sec = msec / 1000;
00999 tv.tv_usec = (msec % 1000) * 1000;
01000
01001 int ready = select(fd + 1, &rfds, NULL, NULL, &tv);
01002
01003 if (ready < 0)
01004 VERBOSE(VB_IMPORTANT, "LFireDev: Select Error" + ENO);
01005
01006 if (ready <= 0)
01007 return false;
01008
01009 return true;
01010 }
01011
01012 static QString speed_to_string(uint speed)
01013 {
01014 if (speed > 3)
01015 return QString("Invalid Speed (%1)").arg(speed);
01016
01017 static const uint speeds[] = { 100, 200, 400, 800 };
01018 return QString("%1Mbps").arg(speeds[speed]);
01019 }
01020
01021 static int linux_firewire_device_bus_reset_handler(
01022 raw1394handle_t handle, unsigned int generation)
01023 {
01024 QMutexLocker locker(&LFDPriv::s_lock);
01025
01026 handle_to_lfd_t::iterator it = LFDPriv::s_handle_info.find(handle);
01027
01028 if (it != LFDPriv::s_handle_info.end())
01029 (*it)->SignalReset(generation);
01030
01031 return 0;
01032 }
01033
01034
01035 #define PLUGREPORT_GUID_HI 0x0C
01036 #define PLUGREPORT_GUID_LO 0x10
01037 static bool get_guid(raw1394handle_t handle, nodeid_t node, uint64_t &guid,
01038 bool &temp_unavailable)
01039 {
01040 uint64_t offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_HI;
01041 uint32_t quadlet;
01042 int err = raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
01043 if (-1 == err)
01044 {
01045 temp_unavailable = (errno == 11);
01046 if (!temp_unavailable)
01047 VERBOSE(VB_IMPORTANT, "get_guid 1, Error: " + ENO);
01048 return false;
01049 }
01050 guid = htonl(quadlet);
01051 guid <<= 32;
01052
01053 offset = CSR_REGISTER_BASE + CSR_CONFIG_ROM + PLUGREPORT_GUID_LO;
01054 err = raw1394_read(handle, node, offset, sizeof(uint32_t), &quadlet);
01055 if (-1 == err)
01056 {
01057 temp_unavailable = (errno == 11);
01058 if (!temp_unavailable)
01059 VERBOSE(VB_IMPORTANT, "get_guid 2, Error: " + ENO);
01060 return false;
01061 }
01062 guid += htonl(quadlet);
01063
01064 return true;
01065 }