00001
00009
00010 #include <pthread.h>
00011
00012
00013 #undef always_inline
00014 #include <IOKit/IOMessage.h>
00015 #include <IOKit/IOKitLib.h>
00016 #include <IOKit/firewire/IOFireWireLib.h>
00017 #include <IOKit/firewire/IOFireWireLibIsoch.h>
00018 #include <IOKit/firewire/IOFireWireFamilyCommon.h>
00019 #include <IOKit/avc/IOFireWireAVCLib.h>
00020 #include <CoreServices/CoreServices.h>
00021
00022
00023 #include <algorithm>
00024 #include <vector>
00025 using namespace std;
00026
00027
00028 #include "darwinfirewiredevice.h"
00029 #include "darwinavcinfo.h"
00030 #include "mythlogging.h"
00031 #include "mthread.h"
00032
00033
00034 #include <AVCVideoServices/StringLogger.h>
00035 #include <AVCVideoServices/AVSShared.h>
00036 #include <AVCVideoServices/MPEG2Receiver.h>
00037
00038
00039
00040 namespace AVS
00041 {
00042 IOReturn CreateMPEG2Receiver(
00043 MPEG2Receiver **ppReceiver,
00044 DataPushProc dataPushProcHandler,
00045 void *pDataPushProcRefCon = nil,
00046 MPEG2ReceiverMessageProc messageProcHandler = nil,
00047 void *pMessageProcRefCon = nil,
00048 StringLogger *stringLogger = nil,
00049 IOFireWireLibNubRef nubInterface = nil,
00050 unsigned int cyclesPerSegment =
00051 kCyclesPerReceiveSegment,
00052 unsigned int numSegments =
00053 kNumReceiveSegments,
00054 bool doIRMAllocations = false);
00055 IOReturn DestroyMPEG2Receiver(MPEG2Receiver *pReceiver);
00056 }
00057
00058 #define LOC QString("DFireDev(%1): ").arg(guid_to_string(m_guid))
00059
00060 #define kAnyAvailableIsochChannel 0xFFFFFFFF
00061 #define kNoDataTimeout 300
00062 #define kResetTimeout 1500
00063
00064 static IOReturn dfd_tspacket_handler_thunk(
00065 UInt32 tsPacketCount, UInt32 **ppBuf, void *callback_data);
00066 static void dfd_update_device_list(void *dfd, io_iterator_t iterator);
00067 static void dfd_streaming_log_message(char *pString);
00068 void *dfd_controller_thunk(void *param);
00069 void dfd_stream_msg(UInt32 msg, UInt32 param1,
00070 UInt32 param2, void *callback_data);
00071 int dfd_no_data_notification(void *callback_data);
00072
00073 class DFDPriv
00074 {
00075 public:
00076 DFDPriv() :
00077 controller_thread_cf_ref(NULL), controller_thread_running(false),
00078 notify_port(NULL), notify_source(NULL), deviter(NULL),
00079 actual_fwchan(-1), is_streaming(false), avstream(NULL), logger(NULL),
00080 no_data_cnt(0), no_data_timer_set(false)
00081 {
00082 logger = new AVS::StringLogger(dfd_streaming_log_message);
00083 }
00084
00085 ~DFDPriv()
00086 {
00087 avcinfo_list_t::iterator it = devices.begin();
00088 for (; it != devices.end(); ++it)
00089 delete (*it);
00090 devices.clear();
00091
00092 if (logger)
00093 {
00094 delete logger;
00095 logger = NULL;
00096 }
00097 }
00098
00099 pthread_t controller_thread;
00100 CFRunLoopRef controller_thread_cf_ref;
00101 bool controller_thread_running;
00102
00103 IONotificationPortRef notify_port;
00104 CFRunLoopSourceRef notify_source;
00105 io_iterator_t deviter;
00106
00107 int actual_fwchan;
00108 bool is_streaming;
00109 AVS::MPEG2Receiver *avstream;
00110 AVS::StringLogger *logger;
00111 uint no_data_cnt;
00112 bool no_data_timer_set;
00113 MythTimer no_data_timer;
00114
00115 avcinfo_list_t devices;
00116 };
00117
00118 DarwinFirewireDevice::DarwinFirewireDevice(
00119 uint64_t guid, uint subunitid, uint speed) :
00120 FirewireDevice(guid, subunitid, speed),
00121 m_local_node(-1), m_remote_node(-1), m_priv(new DFDPriv())
00122 {
00123
00124
00125 }
00126
00127 DarwinFirewireDevice::~DarwinFirewireDevice()
00128 {
00129 if (IsPortOpen())
00130 {
00131 LOG(VB_GENERAL, LOG_ERR, LOC + "dtor called with open port");
00132 while (IsPortOpen())
00133 ClosePort();
00134 }
00135
00136 if (m_priv)
00137 {
00138 delete m_priv;
00139 m_priv = NULL;
00140 }
00141 }
00142
00143 void DarwinFirewireDevice::RunController(void)
00144 {
00145 m_priv->controller_thread_cf_ref = CFRunLoopGetCurrent();
00146
00147
00148 mach_port_t master_port;
00149 int ret = IOMasterPort(bootstrap_port, &master_port);
00150 if (kIOReturnSuccess == ret)
00151 {
00152 m_priv->notify_port = IONotificationPortCreate(master_port);
00153 m_priv->notify_source = IONotificationPortGetRunLoopSource(
00154 m_priv->notify_port);
00155
00156 CFRunLoopAddSource(m_priv->controller_thread_cf_ref,
00157 m_priv->notify_source,
00158 kCFRunLoopDefaultMode);
00159
00160 ret = IOServiceAddMatchingNotification(
00161 m_priv->notify_port, kIOMatchedNotification,
00162 IOServiceMatching("IOFireWireAVCUnit"),
00163 dfd_update_device_list, this, &m_priv->deviter);
00164 }
00165
00166 if (kIOReturnSuccess == ret)
00167 dfd_update_device_list(this, m_priv->deviter);
00168
00169 m_priv->controller_thread_running = true;
00170
00171 if (kIOReturnSuccess == ret)
00172 CFRunLoopRun();
00173
00174 QMutexLocker locker(&m_lock);
00175
00176 m_priv->controller_thread_running = false;
00177 }
00178
00179 void DarwinFirewireDevice::StartController(void)
00180 {
00181 m_lock.unlock();
00182
00183 pthread_create(&m_priv->controller_thread, NULL,
00184 dfd_controller_thunk, this);
00185
00186 m_lock.lock();
00187 while (!m_priv->controller_thread_running)
00188 {
00189 m_lock.unlock();
00190 usleep(5000);
00191 m_lock.lock();
00192 }
00193 }
00194
00195 void DarwinFirewireDevice::StopController(void)
00196 {
00197 if (!m_priv->controller_thread_running)
00198 return;
00199
00200 if (m_priv->deviter)
00201 {
00202 IOObjectRelease(m_priv->deviter);
00203 m_priv->deviter = NULL;
00204 }
00205
00206 if (m_priv->notify_source)
00207 {
00208 CFRunLoopSourceInvalidate(m_priv->notify_source);
00209 m_priv->notify_source = NULL;
00210 }
00211
00212 if (m_priv->notify_port)
00213 {
00214 IONotificationPortDestroy(m_priv->notify_port);
00215 m_priv->notify_port = NULL;
00216 }
00217
00218 CFRunLoopStop(m_priv->controller_thread_cf_ref);
00219
00220 while (m_priv->controller_thread_running)
00221 {
00222 m_lock.unlock();
00223 usleep(100 * 1000);
00224 m_lock.lock();
00225 }
00226 }
00227
00228 bool DarwinFirewireDevice::OpenPort(void)
00229 {
00230 QMutexLocker locker(&m_lock);
00231
00232 LOG(VB_RECORD, LOG_INFO, LOC + "OpenPort()");
00233
00234 if (GetInfoPtr() && GetInfoPtr()->IsPortOpen())
00235 {
00236 m_open_port_cnt++;
00237 return true;
00238 }
00239
00240 StartController();
00241
00242 if (!m_priv->controller_thread_running)
00243 {
00244 LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to start firewire thread.");
00245 return false;
00246 }
00247
00248 if (!GetInfoPtr())
00249 {
00250 LOG(VB_GENERAL, LOG_ERR, LOC + "No IEEE-1394 device with our GUID");
00251
00252 StopController();
00253 return false;
00254 }
00255
00256 LOG(VB_RECORD, LOG_INFO, LOC + "Opening AVC Device");
00257 LOG(VB_RECORD, LOG_INFO, LOC + GetInfoPtr()->GetSubunitInfoString());
00258
00259 if (!GetInfoPtr()->IsSubunitType(kAVCSubunitTypeTuner) ||
00260 !GetInfoPtr()->IsSubunitType(kAVCSubunitTypePanel))
00261 {
00262 LOG(VB_GENERAL, LOG_ERR, LOC + QString("No STB at guid: 0x%1")
00263 .arg(m_guid,0,16));
00264
00265 StopController();
00266 return false;
00267 }
00268
00269 bool ok = GetInfoPtr()->OpenPort(m_priv->controller_thread_cf_ref);
00270 if (!ok)
00271 {
00272 LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to get handle for port");
00273
00274 return false;
00275 }
00276
00277
00278 if (!GetInfoPtr()->GetDeviceNodes(m_local_node, m_remote_node))
00279 {
00280 if (m_local_node < 0)
00281 {
00282 LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to query local node");
00283 m_local_node = 0;
00284 }
00285
00286 if (m_remote_node < 0)
00287 {
00288 LOG(VB_GENERAL, LOG_WARNING, LOC + "Failed to query remote node");
00289 m_remote_node = 0;
00290 }
00291 }
00292
00293 m_open_port_cnt++;
00294
00295 return true;
00296 }
00297
00298 bool DarwinFirewireDevice::ClosePort(void)
00299 {
00300 QMutexLocker locker(&m_lock);
00301
00302 LOG(VB_RECORD, LOG_INFO, LOC + "ClosePort()");
00303
00304 if (m_open_port_cnt < 1)
00305 return false;
00306
00307 m_open_port_cnt--;
00308
00309 if (m_open_port_cnt != 0)
00310 return true;
00311
00312 if (GetInfoPtr() && GetInfoPtr()->IsPortOpen())
00313 {
00314 LOG(VB_RECORD, LOG_INFO, LOC + "Closing AVC Device");
00315
00316 GetInfoPtr()->ClosePort();
00317 }
00318
00319 StopController();
00320 m_local_node = -1;
00321 m_remote_node = -1;
00322
00323 return true;
00324 }
00325
00326 bool DarwinFirewireDevice::OpenAVStream(void)
00327 {
00328 if (IsAVStreamOpen())
00329 return true;
00330
00331 int max_speed = GetMaxSpeed();
00332 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Max Speed: %1, Our speed: %2")
00333 .arg(max_speed).arg(m_speed));
00334 m_speed = min((uint)max_speed, m_speed);
00335
00336 uint fwchan = 0;
00337 bool streaming = IsSTBStreaming(&fwchan);
00338 LOG(VB_GENERAL, LOG_INFO, LOC +
00339 QString("STB is %1already streaming on fwchan: %2")
00340 .arg(streaming?"":"not ").arg(fwchan));
00341
00342
00343
00344
00345 int ret = AVS::CreateMPEG2Receiver(
00346 &m_priv->avstream,
00347 dfd_tspacket_handler_thunk, this,
00348 dfd_stream_msg, this,
00349 m_priv->logger ,
00350 GetInfoPtr()->fw_handle,
00351 AVS::kCyclesPerReceiveSegment,
00352 AVS::kNumReceiveSegments,
00353 true );
00354
00355 if (kIOReturnSuccess != ret)
00356 {
00357 LOG(VB_GENERAL, LOG_ERR, LOC + "Couldn't create A/V stream object");
00358 return false;
00359 }
00360
00361 m_priv->avstream->registerNoDataNotificationCallback(
00362 dfd_no_data_notification, this, kNoDataTimeout);
00363
00364 return true;
00365 }
00366
00367 int DarwinFirewireDevice::GetMaxSpeed(void)
00368 {
00369 IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
00370
00371 if ((*fw_handle)->version < 4)
00372 {
00373
00374 io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
00375
00376 FWAddress addr(0xffff, 0xf0000900, m_remote_node);
00377 uint32_t val;
00378 int ret = (*fw_handle)->ReadQuadlet(
00379 fw_handle, dev, &addr, (UInt32*) &val, false, 0);
00380 val = EndianU32_BtoN(val);
00381
00382 return (ret == kIOReturnSuccess) ? (int)((val>>30) & 0x3) : -1;
00383 }
00384
00385 uint32_t generation = 0;
00386 IOFWSpeed speed;
00387 int ret = (*fw_handle)->GetBusGeneration(fw_handle, (UInt32*)&generation);
00388 if (kIOReturnSuccess == ret)
00389 {
00390 ret = (*fw_handle)->GetSpeedBetweenNodes(
00391 fw_handle, generation, m_remote_node, m_local_node, &speed) ;
00392 }
00393
00394 return (ret == kIOReturnSuccess) ? (int)speed : -1;
00395 }
00396
00397 bool DarwinFirewireDevice::IsSTBStreaming(uint *fw_channel)
00398 {
00399 IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
00400 io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
00401
00402 FWAddress addr(0xffff, 0xf0000904, m_remote_node);
00403 uint32_t val;
00404 int ret = (*fw_handle)->ReadQuadlet(
00405 fw_handle, dev, &addr, (UInt32*) &val, false, 0);
00406 val = EndianU32_BtoN(val);
00407
00408 if (ret != kIOReturnSuccess)
00409 return false;
00410
00411 if (val & (kIOFWPCRBroadcast | kIOFWPCRP2PCount))
00412 {
00413 if (fw_channel)
00414 *fw_channel = (val & kIOFWPCRChannel) >> kIOFWPCRChannelPhase;
00415
00416 return true;
00417 }
00418
00419 return false;
00420 }
00421
00422 bool DarwinFirewireDevice::CloseAVStream(void)
00423 {
00424 if (!m_priv->avstream)
00425 return true;
00426
00427 StopStreaming();
00428
00429 LOG(VB_RECORD, LOG_INFO, LOC + "Destroying A/V stream object");
00430 AVS::DestroyMPEG2Receiver(m_priv->avstream);
00431 m_priv->avstream = NULL;
00432
00433 return true;
00434 }
00435
00436 bool DarwinFirewireDevice::IsAVStreamOpen(void) const
00437 {
00438 return m_priv->avstream;
00439 }
00440
00441 bool DarwinFirewireDevice::ResetBus(void)
00442 {
00443 LOG(VB_GENERAL, LOG_DEBUG, LOC + "ResetBus() -- begin");
00444
00445 if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
00446 return false;
00447
00448 IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
00449 bool ok = (*fw_handle)->BusReset(fw_handle) == kIOReturnSuccess;
00450
00451 if (!ok)
00452 LOG(VB_GENERAL, LOG_ERR, LOC + "Bus Reset failed" + ENO);
00453
00454 LOG(VB_GENERAL, LOG_DEBUG, LOC + "ResetBus() -- end");
00455
00456 return ok;
00457 }
00458
00459 bool DarwinFirewireDevice::StartStreaming(void)
00460 {
00461 if (m_priv->is_streaming)
00462 return m_priv->is_streaming;
00463
00464 LOG(VB_RECORD, LOG_INFO, LOC + "Starting A/V streaming");
00465
00466 if (!IsAVStreamOpen() && !OpenAVStream())
00467 {
00468 LOG(VB_GENERAL, LOG_ERR, LOC + "Starting A/V streaming: FAILED");
00469 return false;
00470 }
00471
00472 m_priv->avstream->setReceiveIsochChannel(kAnyAvailableIsochChannel);
00473 m_priv->avstream->setReceiveIsochSpeed((IOFWSpeed) m_speed);
00474 int ret = m_priv->avstream->startReceive();
00475
00476 m_priv->is_streaming = (kIOReturnSuccess == ret);
00477
00478 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Starting A/V streaming: %1")
00479 .arg((m_priv->is_streaming)?"success":"failure"));
00480
00481 return m_priv->is_streaming;
00482 }
00483
00484 bool DarwinFirewireDevice::StopStreaming(void)
00485 {
00486 if (!m_priv->is_streaming)
00487 return true;
00488
00489 LOG(VB_RECORD, LOG_INFO, LOC + "Stopping A/V streaming");
00490
00491 bool ok = (kIOReturnSuccess == m_priv->avstream->stopReceive());
00492 m_priv->is_streaming = !ok;
00493
00494 if (!ok)
00495 {
00496 LOG(VB_RECORD, LOG_ERR, LOC + "Failed to stop A/V streaming");
00497 return false;
00498 }
00499
00500 LOG(VB_RECORD, LOG_INFO, LOC + "Stopped A/V streaming");
00501 return true;
00502 }
00503
00504 bool DarwinFirewireDevice::SendAVCCommand(const vector<uint8_t> &cmd,
00505 vector<uint8_t> &result,
00506 int retry_cnt)
00507 {
00508 return GetInfoPtr()->SendAVCCommand(cmd, result, retry_cnt);
00509 }
00510
00511 bool DarwinFirewireDevice::IsPortOpen(void) const
00512 {
00513 QMutexLocker locker(&m_lock);
00514
00515 if (!GetInfoPtr())
00516 return false;
00517
00518 return GetInfoPtr()->IsPortOpen();
00519 }
00520
00521 void DarwinFirewireDevice::AddListener(TSDataListener *listener)
00522 {
00523 QMutexLocker locker(&m_lock);
00524
00525 FirewireDevice::AddListener(listener);
00526
00527 if (!m_listeners.empty())
00528 StartStreaming();
00529 }
00530
00531 void DarwinFirewireDevice::RemoveListener(TSDataListener *listener)
00532 {
00533 QMutexLocker locker(&m_lock);
00534
00535 FirewireDevice::RemoveListener(listener);
00536
00537 if (m_priv->is_streaming && m_listeners.empty())
00538 {
00539 StopStreaming();
00540 CloseAVStream();
00541 }
00542 }
00543
00544 void DarwinFirewireDevice::BroadcastToListeners(
00545 const unsigned char *data, uint dataSize)
00546 {
00547 QMutexLocker locker(&m_lock);
00548 FirewireDevice::BroadcastToListeners(data, dataSize);
00549 }
00550
00551 void DarwinFirewireDevice::ProcessNoDataMessage(void)
00552 {
00553 if (m_priv->no_data_timer_set)
00554 {
00555 int short_interval = kNoDataTimeout + (kNoDataTimeout>>1);
00556 bool recent = m_priv->no_data_timer.elapsed() <= short_interval;
00557 m_priv->no_data_cnt = (recent) ? m_priv->no_data_cnt + 1 : 1;
00558 }
00559 m_priv->no_data_timer_set = true;
00560 m_priv->no_data_timer.start();
00561
00562 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No Input in %1 msecs")
00563 .arg(m_priv->no_data_cnt * kNoDataTimeout));
00564
00565 if (m_priv->no_data_cnt > (kResetTimeout / kNoDataTimeout))
00566 {
00567 m_priv->no_data_timer_set = false;
00568 m_priv->no_data_cnt = 0;
00569 ResetBus();
00570 }
00571 }
00572
00573 void DarwinFirewireDevice::ProcessStreamingMessage(
00574 uint32_t msg, uint32_t param1, uint32_t param2)
00575 {
00576 int plug_number = 0;
00577
00578 if (AVS::kMpeg2ReceiverAllocateIsochPort == msg)
00579 {
00580 int speed = param1, fw_channel = param2;
00581
00582 bool ok = UpdatePlugRegister(
00583 plug_number, fw_channel, speed, true, false);
00584
00585 LOG(VB_GENERAL, LOG_INFO, LOC + QString("AllocateIsochPort(%1,%2) %3")
00586 .arg(fw_channel).arg(speed).arg(((ok)?"ok":"error")));
00587 }
00588 else if (AVS::kMpeg2ReceiverReleaseIsochPort == msg)
00589 {
00590 int ret = UpdatePlugRegister(plug_number, -1, -1, false, true);
00591
00592 LOG(VB_GENERAL, LOG_INFO, LOC + QString("ReleaseIsochPort %1")
00593 .arg((kIOReturnSuccess == ret)?"ok":"error"));
00594 }
00595 else if (AVS::kMpeg2ReceiverDCLOverrun == msg)
00596 {
00597 LOG(VB_GENERAL, LOG_ERR, LOC + "DCL Overrun");
00598 }
00599 else if (AVS::kMpeg2ReceiverReceivedBadPacket == msg)
00600 {
00601 LOG(VB_GENERAL, LOG_ERR, LOC + "Received Bad Packet");
00602 }
00603 else
00604 {
00605 LOG(VB_GENERAL, LOG_INFO, LOC +
00606 QString("Streaming Message: %1").arg(msg));
00607 }
00608 }
00609
00610 vector<AVCInfo> DarwinFirewireDevice::GetSTBList(void)
00611 {
00612 vector<AVCInfo> list;
00613
00614 {
00615 DarwinFirewireDevice dev(0,0,0);
00616
00617 dev.m_lock.lock();
00618 dev.StartController();
00619 dev.m_lock.unlock();
00620
00621 list = dev.GetSTBListPrivate();
00622
00623 dev.m_lock.lock();
00624 dev.StopController();
00625 dev.m_lock.unlock();
00626 }
00627
00628 return list;
00629 }
00630
00631 vector<AVCInfo> DarwinFirewireDevice::GetSTBListPrivate(void)
00632 {
00633 #if 0
00634 LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- begin");
00635 #endif
00636 QMutexLocker locker(&m_lock);
00637 #if 0
00638 LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- got lock");
00639 #endif
00640
00641 vector<AVCInfo> list;
00642
00643 avcinfo_list_t::iterator it = m_priv->devices.begin();
00644 for (; it != m_priv->devices.end(); ++it)
00645 {
00646 if ((*it)->IsSubunitType(kAVCSubunitTypeTuner) &&
00647 (*it)->IsSubunitType(kAVCSubunitTypePanel))
00648 {
00649 list.push_back(*(*it));
00650 }
00651 }
00652
00653 #if 0
00654 LOG(VB_GENERAL, LOG_DEBUG, LOC + "GetSTBListPrivate -- end");
00655 #endif
00656 return list;
00657 }
00658
00659 void DarwinFirewireDevice::UpdateDeviceListItem(uint64_t guid, void *pitem)
00660 {
00661 QMutexLocker locker(&m_lock);
00662
00663 avcinfo_list_t::iterator it = m_priv->devices.find(guid);
00664
00665 if (it == m_priv->devices.end())
00666 {
00667 DarwinAVCInfo *ptr = new DarwinAVCInfo();
00668
00669 LOG(VB_GENERAL, LOG_INFO, LOC +
00670 QString("Adding 0x%1").arg(guid, 0, 16));
00671
00672 m_priv->devices[guid] = ptr;
00673 it = m_priv->devices.find(guid);
00674 }
00675
00676 io_object_t &item = *((io_object_t*) pitem);
00677 if (it != m_priv->devices.end())
00678 {
00679 LOG(VB_GENERAL, LOG_INFO, LOC +
00680 QString("Updating 0x%1").arg(guid, 0, 16));
00681 (*it)->Update(guid, this, m_priv->notify_port,
00682 m_priv->controller_thread_cf_ref, item);
00683 }
00684 }
00685
00686 DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void)
00687 {
00688 avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
00689 return (it == m_priv->devices.end()) ? NULL : *it;
00690 }
00691
00692 const DarwinAVCInfo *DarwinFirewireDevice::GetInfoPtr(void) const
00693 {
00694 avcinfo_list_t::iterator it = m_priv->devices.find(m_guid);
00695 return (it == m_priv->devices.end()) ? NULL : *it;
00696 }
00697
00698
00699 bool DarwinFirewireDevice::UpdatePlugRegisterPrivate(
00700 uint plug_number, int new_fw_chan, int new_speed,
00701 bool add_plug, bool remove_plug)
00702 {
00703 if (!GetInfoPtr())
00704 return false;
00705
00706 IOFireWireLibDeviceRef fw_handle = GetInfoPtr()->fw_handle;
00707 if (!fw_handle)
00708 return false;
00709
00710 io_object_t dev = (*fw_handle)->GetDevice(fw_handle);
00711
00712
00713 uint low_addr = kPCRBaseAddress + 4 + (plug_number << 2);
00714 FWAddress addr(0xffff, low_addr, m_remote_node);
00715 uint32_t old_plug_val;
00716 if (kIOReturnSuccess != (*fw_handle)->ReadQuadlet(
00717 fw_handle, dev, &addr, (UInt32*) &old_plug_val, false, 0))
00718 {
00719 return false;
00720 }
00721 old_plug_val = EndianU32_BtoN(old_plug_val);
00722
00723 int old_plug_cnt = (old_plug_val >> 24) & 0x3f;
00724 int old_fw_chan = (old_plug_val >> 16) & 0x3f;
00725 int old_speed = (old_plug_val >> 14) & 0x03;
00726
00727 int new_plug_cnt = (int) old_plug_cnt;
00728 new_plug_cnt += ((add_plug) ? 1 : 0) - ((remove_plug) ? 1 : 0);
00729 if ((new_plug_cnt > 0x3f) || (new_plug_cnt < 0))
00730 {
00731 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Invalid Plug Count %1")
00732 .arg(new_plug_cnt));
00733 return false;
00734 }
00735
00736 new_fw_chan = (new_fw_chan >= 0) ? new_fw_chan : old_fw_chan;
00737 if (old_plug_cnt && (new_fw_chan != old_fw_chan))
00738 {
00739 LOG(VB_GENERAL, LOG_WARNING, LOC +
00740 "Ignoring FWChan change request, plug already open");
00741
00742 new_fw_chan = old_fw_chan;
00743 }
00744
00745 new_speed = (new_speed >= 0) ? new_speed : old_speed;
00746 if (old_plug_cnt && (new_speed != old_speed))
00747 {
00748 LOG(VB_GENERAL, LOG_WARNING, LOC +
00749 "Ignoring speed change request, plug already open");
00750
00751 new_speed = old_speed;
00752 }
00753
00754 uint32_t new_plug_val = old_plug_val;
00755
00756 new_plug_val &= ~(0x3f<<24);
00757 new_plug_val &= (remove_plug) ? ~kIOFWPCRBroadcast : ~0x0;
00758 new_plug_val |= (new_plug_cnt & 0x3f) << 24;
00759
00760 new_plug_val &= ~(0x3f<<16);
00761 new_plug_val |= (new_fw_chan & 0x3F) << 16;
00762
00763 new_plug_val &= ~(0x03<<14);
00764 new_plug_val |= (new_speed & 0x03) << 14;
00765
00766 old_plug_val = EndianU32_NtoB(old_plug_val);
00767 new_plug_val = EndianU32_NtoB(new_plug_val);
00768
00769 return (kIOReturnSuccess == (*fw_handle)->CompareSwap(
00770 fw_handle, dev, &addr, old_plug_val, new_plug_val, false, 0));
00771 }
00772
00773 void DarwinFirewireDevice::HandleBusReset(void)
00774 {
00775 int plug_number = 0;
00776 if (!GetInfoPtr())
00777 return;
00778
00779 int fw_channel = m_priv->actual_fwchan;
00780 bool ok = UpdatePlugRegister(plug_number, fw_channel,
00781 m_speed, true, false);
00782 if (!ok)
00783 {
00784 ok = UpdatePlugRegister(plug_number, kAnyAvailableIsochChannel,
00785 m_speed, true, false);
00786 }
00787
00788 if (!ok)
00789 LOG(VB_GENERAL, LOG_ERR, LOC + "Reset: Failed to reconnect");
00790 else
00791 LOG(VB_RECORD, LOG_INFO, LOC + "Reset: Reconnected succesfully");
00792 }
00793
00794 bool DarwinFirewireDevice::UpdatePlugRegister(
00795 uint plug_number, int fw_chan, int speed,
00796 bool add_plug, bool remove_plug, uint retry_cnt)
00797 {
00798 if (!GetInfoPtr() || !GetInfoPtr()->fw_handle)
00799 return false;
00800
00801 bool ok = false;
00802
00803 for (uint i = 0; (i < retry_cnt) && !ok; i++)
00804 {
00805 ok = UpdatePlugRegisterPrivate(
00806 plug_number, fw_chan, speed, add_plug, remove_plug);
00807 }
00808
00809 m_priv->actual_fwchan = (ok) ? fw_chan : kAnyAvailableIsochChannel;
00810
00811 return ok;
00812 }
00813
00814 void DarwinFirewireDevice::HandleDeviceChange(uint messageType)
00815 {
00816 QString loc = LOC + "HandleDeviceChange: ";
00817
00818 if (kIOMessageServiceIsTerminated == messageType)
00819 {
00820 LOG(VB_RECORD, LOG_INFO, loc + "Disconnect");
00821
00822 return;
00823 }
00824
00825 if (kIOMessageServiceIsAttemptingOpen == messageType)
00826 {
00827 LOG(VB_RECORD, LOG_INFO, loc + "Attempting open");
00828 return;
00829 }
00830
00831 if (kIOMessageServiceWasClosed == messageType)
00832 {
00833 LOG(VB_RECORD, LOG_INFO, loc + "Device Closed");
00834
00835 return;
00836 }
00837
00838 if (kIOMessageServiceIsSuspended == messageType)
00839 {
00840 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsSuspended");
00841
00842 return;
00843 }
00844
00845 if (kIOMessageServiceIsResumed == messageType)
00846 {
00847
00848 HandleBusReset();
00849 }
00850
00851 if (kIOMessageServiceIsTerminated == messageType)
00852 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsTerminated");
00853 else if (kIOMessageServiceIsRequestingClose == messageType)
00854 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsRequestingClose");
00855 else if (kIOMessageServiceIsAttemptingOpen == messageType)
00856 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsAttemptingOpen");
00857 else if (kIOMessageServiceWasClosed == messageType)
00858 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceWasClosed");
00859 else if (kIOMessageServiceBusyStateChange == messageType)
00860 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceBusyStateChange");
00861 else if (kIOMessageCanDevicePowerOff == messageType)
00862 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageCanDevicePowerOff");
00863 else if (kIOMessageDeviceWillPowerOff == messageType)
00864 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageDeviceWillPowerOff");
00865 else if (kIOMessageDeviceWillNotPowerOff == messageType)
00866 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageDeviceWillNotPowerOff");
00867 else if (kIOMessageDeviceHasPoweredOn == messageType)
00868 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageDeviceHasPoweredOn");
00869 else if (kIOMessageCanSystemPowerOff == messageType)
00870 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageCanSystemPowerOff");
00871 else if (kIOMessageSystemWillPowerOff == messageType)
00872 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillPowerOff");
00873 else if (kIOMessageSystemWillNotPowerOff == messageType)
00874 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillNotPowerOff");
00875 else if (kIOMessageCanSystemSleep == messageType)
00876 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageCanSystemSleep");
00877 else if (kIOMessageSystemWillSleep == messageType)
00878 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillSleep");
00879 else if (kIOMessageSystemWillNotSleep == messageType)
00880 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillNotSleep");
00881 else if (kIOMessageSystemHasPoweredOn == messageType)
00882 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemHasPoweredOn");
00883 else if (kIOMessageSystemWillRestart == messageType)
00884 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageSystemWillRestart");
00885 else
00886 {
00887 LOG(VB_RECORD, LOG_ERR, loc + QString("unknown message 0x%1")
00888 .arg(messageType, 0, 16));
00889 }
00890 }
00891
00892
00893
00894 void *dfd_controller_thunk(void *callback_data)
00895 {
00896 MThread::ThreadSetup("DarwinController");
00897 reinterpret_cast<DarwinFirewireDevice*>(callback_data)->RunController();
00898 MThread::ThreadCleanup();
00899 return NULL;
00900 }
00901
00902 void dfd_update_device_list_item(
00903 DarwinFirewireDevice *dev, uint64_t guid, void *item)
00904 {
00905 dev->UpdateDeviceListItem(guid, item);
00906 }
00907
00908 int dfd_no_data_notification(void *callback_data)
00909 {
00910 reinterpret_cast<DarwinFirewireDevice*>(callback_data)->
00911 ProcessNoDataMessage();
00912
00913 return kIOReturnSuccess;
00914 }
00915
00916 void dfd_stream_msg(UInt32 msg, UInt32 param1,
00917 UInt32 param2, void *callback_data)
00918 {
00919 reinterpret_cast<DarwinFirewireDevice*>(callback_data)->
00920 ProcessStreamingMessage(msg, param1, param2);
00921 }
00922
00923 int dfd_tspacket_handler(uint tsPacketCount, uint32_t **ppBuf,
00924 void *callback_data)
00925 {
00926 DarwinFirewireDevice *fw =
00927 reinterpret_cast<DarwinFirewireDevice*>(callback_data);
00928
00929 if (!fw)
00930 return kIOReturnBadArgument;
00931
00932 for (uint32_t i = 0; i < tsPacketCount; ++i)
00933 fw->BroadcastToListeners((const unsigned char*) ppBuf[i], 188);
00934
00935 return kIOReturnSuccess;
00936 }
00937
00938 static IOReturn dfd_tspacket_handler_thunk(
00939 UInt32 tsPacketCount, UInt32 **ppBuf, void *callback_data)
00940 {
00941 return dfd_tspacket_handler(
00942 tsPacketCount, (uint32_t**)ppBuf, callback_data);
00943 }
00944
00945 static void dfd_update_device_list(void *dfd, io_iterator_t deviter)
00946 {
00947 DarwinFirewireDevice *dev = reinterpret_cast<DarwinFirewireDevice*>(dfd);
00948
00949 io_object_t it = NULL;
00950 while ((it = IOIteratorNext(deviter)))
00951 {
00952 uint64_t guid = 0;
00953
00954 CFMutableDictionaryRef props;
00955 int ret = IORegistryEntryCreateCFProperties(
00956 it, &props, kCFAllocatorDefault, kNilOptions);
00957
00958 if (kIOReturnSuccess == ret)
00959 {
00960 CFNumberRef GUIDDesc = (CFNumberRef)
00961 CFDictionaryGetValue(props, CFSTR("GUID"));
00962 CFNumberGetValue(GUIDDesc, kCFNumberSInt64Type, &guid);
00963 CFRelease(props);
00964 dfd_update_device_list_item(dev, guid, &it);
00965 }
00966 }
00967 }
00968
00969 static void dfd_streaming_log_message(char *msg)
00970 {
00971 LOG(VB_RECORD, LOG_INFO, QString("MPEG2Receiver: %1").arg(msg));
00972 }