|
MythTV
0.26-pre
|
00001 00009 // POSIX headers 00010 #include <pthread.h> 00011 00012 // OS X headers 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> // for EndianU32_BtoN() etc. 00021 00022 // Std C++ headers 00023 #include <algorithm> 00024 #include <vector> 00025 using namespace std; 00026 00027 // MythTV headers 00028 #include "darwinfirewiredevice.h" 00029 #include "darwinavcinfo.h" 00030 #include "mythlogging.h" 00031 #include "mthread.h" 00032 00033 // Apple Firewire example headers 00034 #include <AVCVideoServices/StringLogger.h> 00035 #include <AVCVideoServices/AVSShared.h> 00036 #include <AVCVideoServices/MPEG2Receiver.h> 00037 00038 // header not used because it also requires MPEG2Transmitter.h 00039 //#include <AVCVideoServices/FireWireMPEG.h> 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 /* msec */ 00062 #define kResetTimeout 1500 /* msec */ 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 // Set up IEEE-1394 bus change notification 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); // ensure that controller_thread_running seen 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 // TODO FIXME -- these can change after a reset... (at least local) 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 // TODO we should use the stream if it already exists, 00343 // this is especially true if it is a broadcast stream... 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 /* StringLogger */, 00350 GetInfoPtr()->fw_handle, 00351 AVS::kCyclesPerReceiveSegment, 00352 AVS::kNumReceiveSegments, 00353 true /* p2p */); 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 // Just get the STB's info & assume we can handle it 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 // Read the register 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 // stop printing no data messages.. don't try to open 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 // fill unit_table 00835 return; 00836 } 00837 00838 if (kIOMessageServiceIsSuspended == messageType) 00839 { 00840 LOG(VB_RECORD, LOG_INFO, loc + "kIOMessageServiceIsSuspended"); 00841 // start of reset 00842 return; 00843 } 00844 00845 if (kIOMessageServiceIsResumed == messageType) 00846 { 00847 // end of reset 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 // Various message callbacks. 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 }
1.7.6.1