fix assertion on XBMC exit
[deb_libcec.git] / src / lib / adapter / RPi / RPiCECAdapterCommunication.cpp
index 5d13368e50a3c569667ab0b812ed3d824b534c50..243223d3f67d0a149d5e37a85bc8daa4e065a0aa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the libCEC(R) library.
  *
- * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
  * libCEC(R) is an original work, containing original code.
  *
  * libCEC(R) is a trademark of Pulse-Eight Limited.
@@ -58,10 +58,19 @@ void rpi_cec_callback(void *callback_data, uint32_t p0, uint32_t p1, uint32_t p2
     static_cast<CRPiCECAdapterCommunication *>(callback_data)->OnDataReceived(p0, p1, p2, p3, p4);
 }
 
+// callback for the TV service
+void rpi_tv_callback(void *callback_data, uint32_t reason, uint32_t p0, uint32_t p1)
+{
+  if (callback_data)
+    static_cast<CRPiCECAdapterCommunication *>(callback_data)->OnTVServiceCallback(reason, p0, p1);
+}
+
 CRPiCECAdapterCommunication::CRPiCECAdapterCommunication(IAdapterCommunicationCallback *callback) :
     IAdapterCommunication(callback),
     m_logicalAddress(CECDEVICE_UNKNOWN),
-    m_bLogicalAddressChanged(false)
+    m_bLogicalAddressChanged(false),
+    m_previousLogicalAddress(CECDEVICE_FREEUSE),
+    m_bLogicalAddressRegistered(false)
 {
   m_queue = new CRPiCECAdapterMessageQueue(this);
 }
@@ -105,11 +114,35 @@ bool CRPiCECAdapterCommunication::IsInitialised(void)
   return m_bInitialised;
 }
 
+void CRPiCECAdapterCommunication::OnTVServiceCallback(uint32_t reason, uint32_t UNUSED(p0), uint32_t UNUSED(p1))
+{
+  switch(reason)
+  {
+  case VC_HDMI_ATTACHED:
+  {
+    uint16_t iNewAddress = GetPhysicalAddress();
+    m_callback->HandlePhysicalAddressChanged(iNewAddress);
+    break;
+  }
+  case VC_HDMI_UNPLUGGED:
+  case VC_HDMI_DVI:
+  case VC_HDMI_HDMI:
+  case VC_HDMI_HDCP_UNAUTH:
+  case VC_HDMI_HDCP_AUTH:
+  case VC_HDMI_HDCP_KEY_DOWNLOAD:
+  case VC_HDMI_HDCP_SRM_DOWNLOAD:
+  default:
+     break;
+  }
+}
+
 void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3)
 {
   VC_CEC_NOTIFY_T reason = (VC_CEC_NOTIFY_T)CEC_CB_REASON(header);
 
+#ifdef CEC_DEBUGGING
   LIB_CEC->AddLog(CEC_LOG_DEBUG, "received data: header:%08X p0:%08X p1:%08X p2:%08X p3:%08X reason:%x", header, p0, p1, p2, p3, reason);
+#endif
 
   switch (reason)
   {
@@ -174,6 +207,7 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u
   case VC_CEC_LOGICAL_ADDR:
     {
       CLockObject lock(m_mutex);
+      m_previousLogicalAddress = m_logicalAddress;
       if (CEC_CB_RC(header) == VCHIQ_SUCCESS)
       {
         m_bLogicalAddressChanged = true;
@@ -182,7 +216,7 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u
       }
       else
       {
-        m_logicalAddress = CECDEVICE_BROADCAST;
+        m_logicalAddress = CECDEVICE_FREEUSE;
         LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to change the logical address, reset to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress);
       }
       m_logicalAddressCondition.Signal();
@@ -191,11 +225,16 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u
   case VC_CEC_LOGICAL_ADDR_LOST:
     {
       // the logical address was taken by another device
-      cec_logical_address previousAddress = m_logicalAddress;
+      cec_logical_address previousAddress = m_logicalAddress == CECDEVICE_BROADCAST ? m_previousLogicalAddress : m_logicalAddress;
       m_logicalAddress = CECDEVICE_UNKNOWN;
 
       // notify libCEC that we lost our LA when the connection was initialised
-      if (m_bInitialised)
+      bool bNotify(false);
+      {
+        CLockObject lock(m_mutex);
+        bNotify = m_bInitialised && m_bLogicalAddressRegistered;
+      }
+      if (bNotify)
         m_callback->HandleLogicalAddressLost(previousAddress);
     }
     break;
@@ -262,8 +301,9 @@ bool CRPiCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN
     // enable passive mode
     vc_cec_set_passive(true);
 
-    // register the callback
-    vc_cec_register_callback(((CECSERVICE_CALLBACK_T)rpi_cec_callback), (void*)this);
+    // register the callbacks
+    vc_cec_register_callback(rpi_cec_callback, (void*)this);
+    vc_tv_register_callback(rpi_tv_callback, (void*)this);
 
     // release previous LA
     vc_cec_release_logical_address();
@@ -313,6 +353,9 @@ void CRPiCECAdapterCommunication::Close(void)
     else
       return;
   }
+  if (m_bInitialised)
+    vc_tv_unregister_callback(rpi_tv_callback);
+
   UnregisterLogicalAddress();
 
   // disable passive mode
@@ -340,13 +383,18 @@ cec_adapter_message_state CRPiCECAdapterCommunication::Write(const cec_command &
     return (data.initiator == data.destination) ? ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED : ADAPTER_MESSAGE_STATE_ERROR;
   }
 
-  if (!data.opcode_set && data.initiator == data.destination)
+  if (!m_queue->Write(data, bIsReply))
   {
-    // registration of the logical address would have failed
-    return ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+    if (!data.opcode_set)
+    {
+      return ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+    }
+    
+    return ADAPTER_MESSAGE_STATE_SENT;
   }
 
-  return m_queue->Write(data, bIsReply) ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+  return ADAPTER_MESSAGE_STATE_SENT_ACKED;
+
 }
 
 uint16_t CRPiCECAdapterCommunication::GetFirmwareVersion(void)
@@ -375,7 +423,11 @@ bool CRPiCECAdapterCommunication::UnregisterLogicalAddress(void)
     return true;
 
   LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - releasing previous logical address", __FUNCTION__);
-  m_bLogicalAddressChanged = false;
+  {
+    CLockObject lock(m_mutex);
+    m_bLogicalAddressRegistered = false;
+    m_bLogicalAddressChanged    = false;
+  }
 
   vc_cec_release_logical_address();
 
@@ -407,7 +459,12 @@ bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_addre
     return false;
   }
 
-  return m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged);
+  if (m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged))
+  {
+    m_bLogicalAddressRegistered = true;
+    return true;
+  }
+  return false;
 }
 
 cec_logical_addresses CRPiCECAdapterCommunication::GetLogicalAddresses(void)