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