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