MythTV  master
darwinavcinfo.cpp
Go to the documentation of this file.
1 
7 // Std C++ headers
8 #include <vector>
9 using namespace std;
10 
11 // MythTV headers
12 #include "darwinfirewiredevice.h"
13 #include "darwinavcinfo.h"
14 #include "mythlogging.h"
15 
16 #ifndef kIOFireWireAVCLibUnitInterfaceID2
17 #define kIOFireWireAVCLibUnitInterfaceID2 \
18  CFUUIDGetConstantUUIDWithBytes( \
19  nullptr, \
20  0x85, 0xB5, 0xE9, 0x54, 0x0A, 0xEF, 0x11, 0xD8, \
21  0x8D, 0x19, 0x00, 0x03, 0x93, 0x91, 0x4A, 0xBA)
22 #endif
23 
24 static void dfd_device_change_msg(
25  void* /*dfd*/, io_service_t /*unused*/, natural_t messageType,
26  void* /*unused*/);
27 
28 void DarwinAVCInfo::Update(uint64_t _guid, DarwinFirewireDevice *dev,
29  IONotificationPortRef notify_port,
30  CFRunLoopRef &thread_cf_ref, io_object_t obj)
31 {
32  IOObjectRelease(fw_device_notifier_ref);
33  IOObjectRelease(fw_node_ref);
34  IOObjectRelease(fw_device_ref);
35  IOObjectRelease(fw_service_ref);
36  IOObjectRelease(avc_service_ref);
37 
38  avc_service_ref = obj;
39 
40  IORegistryEntryGetParentEntry(
41  avc_service_ref, kIOServicePlane, &fw_service_ref);
42  IORegistryEntryGetParentEntry(
43  fw_service_ref, kIOServicePlane, &fw_device_ref);
44  IORegistryEntryGetParentEntry(
45  fw_device_ref, kIOServicePlane, &fw_node_ref);
46 
47  if (notify_port)
48  {
49  IOServiceAddInterestNotification(
50  notify_port, obj, kIOGeneralInterest,
52  &fw_device_notifier_ref);
53  }
54 
55  if (m_guid == _guid)
56  return; // we're done
57 
58  m_guid = _guid;
59 
61  // get basic info
62 
63  CFMutableDictionaryRef props;
64  int ret = IORegistryEntryCreateCFProperties(
65  obj, &props, kCFAllocatorDefault, kNilOptions);
66  if (kIOReturnSuccess != ret)
67  return; // this is bad
68 
69  auto specDesc = (CFNumberRef)
70  CFDictionaryGetValue(props, CFSTR("Unit_Spec_ID"));
71  CFNumberGetValue(specDesc, kCFNumberSInt32Type, &m_specid);
72 
73  auto typeDesc = (CFNumberRef)
74  CFDictionaryGetValue(props, CFSTR("Unit_Type"));
75  CFNumberGetValue(typeDesc, kCFNumberSInt32Type, &m_modelid);
76 
77  auto vendorDesc = (CFNumberRef)
78  CFDictionaryGetValue(props, CFSTR("Vendor_ID"));
79  CFNumberGetValue(vendorDesc, kCFNumberSInt32Type, &m_vendorid);
80 
81  auto versionDesc = (CFNumberRef)
82  CFDictionaryGetValue(props, CFSTR("Unit_SW_Version"));
83  CFNumberGetValue(versionDesc, kCFNumberSInt32Type, &m_firmware_revision);
84 
85  auto tmp0 = (CFStringRef)
86  CFDictionaryGetValue(props, CFSTR("FireWire Product Name"));
87  if (tmp0)
88  {
89  char tmp1[1024];
90  memset(tmp1, 0, sizeof(tmp1));
91  CFStringGetCString(tmp0, tmp1, sizeof(tmp1) - sizeof(char),
92  kCFStringEncodingMacRoman);
93  m_product_name = QString("%1").arg(tmp1);
94  }
95 
96  CFRelease(props);
97 
99  // get subunit info
100 
101  LOG(VB_RECORD, LOG_INFO, QString("Scanning guid: 0x%1").arg(m_guid, 0, 16));
102 
103  bool wasOpen = IsAVCInterfaceOpen();
104  if (OpenAVCInterface(thread_cf_ref))
105  {
106  if (!GetSubunitInfo())
107  {
108  LOG(VB_GENERAL, LOG_ERR, "GetSubunitInfo failed");
109  }
110 
111  if (!wasOpen)
112  CloseAVCInterface();
113  }
114 }
115 
117  const vector<uint8_t> &cmd,
118  vector<uint8_t> &result,
119  int /*retry_cnt*/)
120 {
121  result.clear();
122 
123  uint32_t result_length = 4096;
124  uint8_t response[4096];
125 
126  if (!avc_handle)
127  return false;
128 
129  int ret = (*avc_handle)->
130  AVCCommand(avc_handle, (const UInt8*) &cmd[0], cmd.size(),
131  response, (UInt32*) &result_length);
132 
133  if (ret != kIOReturnSuccess)
134  return false;
135 
136  if (result_length)
137  result.insert(result.end(), response, response + result_length);
138 
139  return true;
140 }
141 
142 bool DarwinAVCInfo::OpenPort(CFRunLoopRef &thread_cf_ref)
143 {
144  if (IsPortOpen())
145  return true;
146 
147  if (!OpenAVCInterface(thread_cf_ref))
148  return false;
149 
150  if (!OpenDeviceInterface(thread_cf_ref))
151  {
152  CloseAVCInterface();
153  return false;
154  }
155 
156  return true;
157 }
158 
160 {
161  CloseDeviceInterface();
162  CloseAVCInterface();
163  return true;
164 }
165 
166 bool DarwinAVCInfo::OpenAVCInterface(CFRunLoopRef &thread_cf_ref)
167 {
168  if (IsAVCInterfaceOpen())
169  return true;
170 
171  if (!avc_service_ref)
172  return false;
173 
174  IOCFPlugInInterface **input_plug;
175  int32_t dummy;
176  int ret = IOCreatePlugInInterfaceForService(
177  avc_service_ref, kIOFireWireAVCLibUnitTypeID, kIOCFPlugInInterfaceID,
178  &input_plug, (SInt32*) &dummy);
179 
180  if (kIOReturnSuccess != ret)
181  return false;
182 
183  // Try to get post-Jaguar interface
184  HRESULT err = (*input_plug)->QueryInterface(
185  input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID2),
186  (void**) &avc_handle);
187 
188  // On failure, try Jaguar interface
189  if (S_OK != err)
190  {
191  err = (*input_plug)->QueryInterface(
192  input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID),
193  (void**) &avc_handle);
194  }
195 
196  if (S_OK != err)
197  {
198  (*input_plug)->Release(input_plug);
199  return false;
200  }
201 
202  // Add avc_handle to the event loop
203  ret = (*avc_handle)->addCallbackDispatcherToRunLoop(
204  avc_handle, thread_cf_ref);
205 
206  (*input_plug)->Release(input_plug);
207 
208  if (kIOReturnSuccess != ret)
209  {
210  (*avc_handle)->Release(avc_handle);
211  avc_handle = nullptr;
212  return false;
213  }
214 
215  ret = (*avc_handle)->open(avc_handle);
216  if (kIOReturnSuccess != ret)
217  {
218  (*avc_handle)->Release(avc_handle);
219  avc_handle = nullptr;
220  return false;
221  }
222 
223  return true;
224 }
225 
227 {
228  if (!avc_handle)
229  return;
230 
231  (*avc_handle)->removeCallbackDispatcherFromRunLoop(avc_handle);
232  (*avc_handle)->close(avc_handle);
233  (*avc_handle)->Release(avc_handle);
234 
235  avc_handle = nullptr;
236 }
237 
238 bool DarwinAVCInfo::OpenDeviceInterface(CFRunLoopRef &thread_cf_ref)
239 {
240  if (fw_handle)
241  return true;
242 
243  if (!avc_handle)
244  return false;
245 
246  IOCFPlugInInterface **input_plug;
247  int32_t dummy;
248  int ret = IOCreatePlugInInterfaceForService(
249  fw_device_ref, kIOFireWireLibTypeID, kIOCFPlugInInterfaceID,
250  &input_plug, (SInt32*) &dummy);
251 
252  if (kIOReturnSuccess != ret)
253  return false;
254 
255  HRESULT err = (*input_plug)->QueryInterface(
256  input_plug, CFUUIDGetUUIDBytes(kIOFireWireNubInterfaceID),
257  (void**) &fw_handle);
258 
259  if (S_OK != err)
260  {
261  (*input_plug)->Release(input_plug);
262  return false;
263  }
264 
265  // Add fw_handle to the event loop
266  ret = (*fw_handle)->AddCallbackDispatcherToRunLoop(
267  fw_handle, thread_cf_ref);
268 
269  (*input_plug)->Release(input_plug);
270 
271  if (kIOReturnSuccess == ret)
272  {
273  // open the interface
274  ret = (*fw_handle)->OpenWithSessionRef(
275  fw_handle, (*avc_handle)->getSessionRef(avc_handle));
276  }
277 
278  if (kIOReturnSuccess != ret)
279  {
280  (*fw_handle)->Release(fw_handle);
281  fw_handle = nullptr;
282  return false;
283  }
284 
285  return true;
286 }
287 
289 {
290  if (!fw_handle)
291  return;
292 
293  (*fw_handle)->RemoveCallbackDispatcherFromRunLoop(fw_handle);
294  (*fw_handle)->Close(fw_handle);
295  (*fw_handle)->Release(fw_handle);
296 
297  fw_handle = nullptr;
298 }
299 
300 bool DarwinAVCInfo::GetDeviceNodes(int &local_node, int &remote_node)
301 {
302  uint32_t generation = 0;
303  uint16_t node = 0;
304  local_node = -1;
305  remote_node = -1;
306 
307  if ((*fw_handle)->version < 4)
308  {
309  if (kIOReturnSuccess == (*fw_handle)->GetGenerationAndNodeID(
310  fw_handle, (UInt32*) &generation, (UInt16*) &node))
311  {
312  remote_node = node;
313  }
314 
315  if (kIOReturnSuccess == (*fw_handle)->GetLocalNodeID(
316  fw_handle, (UInt16*) &node))
317  {
318  local_node = node;
319  }
320  }
321 
322  int ret = (*fw_handle)->GetBusGeneration(fw_handle, (UInt32*)&generation);
323  if (kIOReturnSuccess == ret)
324  {
325  if (kIOReturnSuccess == (*fw_handle)->GetLocalNodeIDWithGeneration(
326  fw_handle, generation, (UInt16*) &node))
327  {
328  local_node = node;
329  }
330 
331  if (kIOReturnSuccess == (*fw_handle)->GetRemoteNodeID(
332  fw_handle, generation, (UInt16*) &node))
333  {
334  remote_node = node;
335  }
336  }
337 
338  return (local_node >= 0) && (remote_node >= 0);
339 }
340 
342  void *dfd, io_service_t /*unused*/, natural_t messageType, void* /*unused*/)
343 {
344  auto *dev = reinterpret_cast<DarwinFirewireDevice*>(dfd);
345  dev->HandleDeviceChange(messageType);
346 }
DarwinAVCInfo::OpenDeviceInterface
bool OpenDeviceInterface(CFRunLoopRef &thread_cf_ref)
Definition: darwinavcinfo.cpp:238
darwinfirewiredevice.h
DarwinFirewireDevice
Definition: darwinfirewiredevice.h:11
arg
arg(title).arg(filename).arg(doDelete))
DarwinAVCInfo::GetDeviceNodes
bool GetDeviceNodes(int &local_node, int &remote_node)
Definition: darwinavcinfo.cpp:300
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
DarwinAVCInfo::OpenPort
bool OpenPort(CFRunLoopRef &thread_cf_ref)
Definition: darwinavcinfo.cpp:142
mythlogging.h
darwinavcinfo.h
DarwinAVCInfo::SendAVCCommand
bool SendAVCCommand(const vector< uint8_t > &cmd, vector< uint8_t > &result, int retry_cnt) override
Definition: darwinavcinfo.cpp:116
DarwinFirewireDevice::HandleDeviceChange
void HandleDeviceChange(uint messageType)
Definition: darwinfirewiredevice.cpp:812
DarwinAVCInfo::Update
void Update(uint64_t _guid, DarwinFirewireDevice *dev, IONotificationPortRef notify_port, CFRunLoopRef &thread_cf_ref, io_object_t obj)
Definition: darwinavcinfo.cpp:28
DarwinAVCInfo::CloseAVCInterface
void CloseAVCInterface(void)
Definition: darwinavcinfo.cpp:226
DarwinAVCInfo::CloseDeviceInterface
void CloseDeviceInterface(void)
Definition: darwinavcinfo.cpp:288
dfd_device_change_msg
static void dfd_device_change_msg(void *, io_service_t, natural_t messageType, void *)
Definition: darwinavcinfo.cpp:341
kIOFireWireAVCLibUnitInterfaceID2
#define kIOFireWireAVCLibUnitInterfaceID2
Definition: darwinavcinfo.cpp:17
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
DarwinAVCInfo::OpenAVCInterface
bool OpenAVCInterface(CFRunLoopRef &thread_cf_ref)
Definition: darwinavcinfo.cpp:166
DarwinAVCInfo::ClosePort
bool ClosePort(void)
Definition: darwinavcinfo.cpp:159