00001
00007
00008 #include <vector>
00009 using namespace std;
00010
00011
00012 #include "darwinfirewiredevice.h"
00013 #include "darwinavcinfo.h"
00014 #include "mythcontext.h"
00015
00016 #ifndef kIOFireWireAVCLibUnitInterfaceID2
00017 #define kIOFireWireAVCLibUnitInterfaceID2 \
00018 CFUUIDGetConstantUUIDWithBytes( \
00019 NULL, \
00020 0x85, 0xB5, 0xE9, 0x54, 0x0A, 0xEF, 0x11, 0xD8, \
00021 0x8D, 0x19, 0x00, 0x03, 0x93, 0x91, 0x4A, 0xBA)
00022 #endif
00023
00024 static void dfd_device_change_msg(
00025 void*, io_service_t, natural_t messageType, void*);
00026
00027 void DarwinAVCInfo::Update(uint64_t _guid, DarwinFirewireDevice *dev,
00028 IONotificationPortRef notify_port,
00029 CFRunLoopRef &thread_cf_ref, io_object_t obj)
00030 {
00031 IOObjectRelease(fw_device_notifier_ref);
00032 IOObjectRelease(fw_node_ref);
00033 IOObjectRelease(fw_device_ref);
00034 IOObjectRelease(fw_service_ref);
00035 IOObjectRelease(avc_service_ref);
00036
00037 avc_service_ref = obj;
00038
00039 IORegistryEntryGetParentEntry(
00040 avc_service_ref, kIOServicePlane, &fw_service_ref);
00041 IORegistryEntryGetParentEntry(
00042 fw_service_ref, kIOServicePlane, &fw_device_ref);
00043 IORegistryEntryGetParentEntry(
00044 fw_device_ref, kIOServicePlane, &fw_node_ref);
00045
00046 if (notify_port)
00047 {
00048 IOServiceAddInterestNotification(
00049 notify_port, obj, kIOGeneralInterest,
00050 dfd_device_change_msg, dev,
00051 &fw_device_notifier_ref);
00052 }
00053
00054 if (guid == _guid)
00055 return;
00056
00057 guid = _guid;
00058
00060
00061
00062 CFMutableDictionaryRef props;
00063 int ret = IORegistryEntryCreateCFProperties(
00064 obj, &props, kCFAllocatorDefault, kNilOptions);
00065 if (kIOReturnSuccess != ret)
00066 return;
00067
00068 CFNumberRef specDesc = (CFNumberRef)
00069 CFDictionaryGetValue(props, CFSTR("Unit_Spec_ID"));
00070 CFNumberGetValue(specDesc, kCFNumberSInt32Type, &specid);
00071
00072 CFNumberRef typeDesc = (CFNumberRef)
00073 CFDictionaryGetValue(props, CFSTR("Unit_Type"));
00074 CFNumberGetValue(typeDesc, kCFNumberSInt32Type, &modelid);
00075
00076 CFNumberRef vendorDesc = (CFNumberRef)
00077 CFDictionaryGetValue(props, CFSTR("Vendor_ID"));
00078 CFNumberGetValue(vendorDesc, kCFNumberSInt32Type, &vendorid);
00079
00080 CFNumberRef versionDesc = (CFNumberRef)
00081 CFDictionaryGetValue(props, CFSTR("Unit_SW_Version"));
00082 CFNumberGetValue(versionDesc, kCFNumberSInt32Type, &firmware_revision);
00083
00084 CFStringRef tmp0 = (CFStringRef)
00085 CFDictionaryGetValue(props, CFSTR("FireWire Product Name"));
00086 if (tmp0)
00087 {
00088 char tmp1[1024];
00089 bzero(tmp1, sizeof(tmp1));
00090 CFStringGetCString(tmp0, tmp1, sizeof(tmp1) - sizeof(char),
00091 kCFStringEncodingMacRoman);
00092 product_name = QString("%1").arg(tmp1);
00093 }
00094
00095 CFRelease(props);
00096
00098
00099
00100 VERBOSE(VB_RECORD, "Scanning guid: 0x"<<hex<<guid<<dec);
00101
00102 bool wasOpen = IsAVCInterfaceOpen();
00103 if (OpenAVCInterface(thread_cf_ref))
00104 {
00105 if (!GetSubunitInfo())
00106 {
00107 VERBOSE(VB_IMPORTANT, "GetSubunitInfo failed");
00108 }
00109
00110 if (!wasOpen)
00111 CloseAVCInterface();
00112 }
00113 }
00114
00115 bool DarwinAVCInfo::SendAVCCommand(
00116 const vector<uint8_t> &cmd,
00117 vector<uint8_t> &result,
00118 int )
00119 {
00120 result.clear();
00121
00122 uint32_t result_length = 4096;
00123 uint8_t response[4096];
00124
00125 if (!avc_handle)
00126 return false;
00127
00128 int ret = (*avc_handle)->
00129 AVCCommand(avc_handle, (const UInt8*) &cmd[0], cmd.size(),
00130 response, (UInt32*) &result_length);
00131
00132 if (ret != kIOReturnSuccess)
00133 return false;
00134
00135 if (result_length)
00136 result.insert(result.end(), response, response + result_length);
00137
00138 return true;
00139 }
00140
00141 bool DarwinAVCInfo::OpenPort(CFRunLoopRef &thread_cf_ref)
00142 {
00143 if (IsPortOpen())
00144 return true;
00145
00146 if (!OpenAVCInterface(thread_cf_ref))
00147 return false;
00148
00149 if (!OpenDeviceInterface(thread_cf_ref))
00150 {
00151 CloseAVCInterface();
00152 return false;
00153 }
00154
00155 return true;
00156 }
00157
00158 bool DarwinAVCInfo::ClosePort(void)
00159 {
00160 CloseDeviceInterface();
00161 CloseAVCInterface();
00162 return true;
00163 }
00164
00165 bool DarwinAVCInfo::OpenAVCInterface(CFRunLoopRef &thread_cf_ref)
00166 {
00167 if (IsAVCInterfaceOpen())
00168 return true;
00169
00170 if (!avc_service_ref)
00171 return false;
00172
00173 IOCFPlugInInterface **input_plug;
00174 int32_t dummy;
00175 int ret = IOCreatePlugInInterfaceForService(
00176 avc_service_ref, kIOFireWireAVCLibUnitTypeID, kIOCFPlugInInterfaceID,
00177 &input_plug, (SInt32*) &dummy);
00178
00179 if (kIOReturnSuccess != ret)
00180 return false;
00181
00182
00183 HRESULT err = (*input_plug)->QueryInterface(
00184 input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID2),
00185 (void**) &avc_handle);
00186
00187
00188 if (S_OK != err)
00189 {
00190 err = (*input_plug)->QueryInterface(
00191 input_plug, CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID),
00192 (void**) &avc_handle);
00193 }
00194
00195 if (S_OK != err)
00196 {
00197 (*input_plug)->Release(input_plug);
00198 return false;
00199 }
00200
00201
00202 ret = (*avc_handle)->addCallbackDispatcherToRunLoop(
00203 avc_handle, thread_cf_ref);
00204
00205 (*input_plug)->Release(input_plug);
00206
00207 if (kIOReturnSuccess != ret)
00208 {
00209 (*avc_handle)->Release(avc_handle);
00210 avc_handle = NULL;
00211 return false;
00212 }
00213
00214 ret = (*avc_handle)->open(avc_handle);
00215 if (kIOReturnSuccess != ret)
00216 {
00217 (*avc_handle)->Release(avc_handle);
00218 avc_handle = NULL;
00219 return false;
00220 }
00221
00222 return true;
00223 }
00224
00225 void DarwinAVCInfo::CloseAVCInterface(void)
00226 {
00227 if (!avc_handle)
00228 return;
00229
00230 (*avc_handle)->removeCallbackDispatcherFromRunLoop(avc_handle);
00231 (*avc_handle)->close(avc_handle);
00232 (*avc_handle)->Release(avc_handle);
00233
00234 avc_handle = NULL;
00235 }
00236
00237 bool DarwinAVCInfo::OpenDeviceInterface(CFRunLoopRef &thread_cf_ref)
00238 {
00239 if (fw_handle)
00240 return true;
00241
00242 if (!avc_handle)
00243 return false;
00244
00245 IOCFPlugInInterface **input_plug;
00246 int32_t dummy;
00247 int ret = IOCreatePlugInInterfaceForService(
00248 fw_device_ref, kIOFireWireLibTypeID, kIOCFPlugInInterfaceID,
00249 &input_plug, (SInt32*) &dummy);
00250
00251 if (kIOReturnSuccess != ret)
00252 return false;
00253
00254 HRESULT err = (*input_plug)->QueryInterface(
00255 input_plug, CFUUIDGetUUIDBytes(kIOFireWireNubInterfaceID),
00256 (void**) &fw_handle);
00257
00258 if (S_OK != err)
00259 {
00260 (*input_plug)->Release(input_plug);
00261 return false;
00262 }
00263
00264
00265 ret = (*fw_handle)->AddCallbackDispatcherToRunLoop(
00266 fw_handle, thread_cf_ref);
00267
00268 (*input_plug)->Release(input_plug);
00269
00270 if (kIOReturnSuccess == ret)
00271 {
00272
00273 ret = (*fw_handle)->OpenWithSessionRef(
00274 fw_handle, (*avc_handle)->getSessionRef(avc_handle));
00275 }
00276
00277 if (kIOReturnSuccess != ret)
00278 {
00279 (*fw_handle)->Release(fw_handle);
00280 fw_handle = NULL;
00281 return false;
00282 }
00283
00284 return true;
00285 }
00286
00287 void DarwinAVCInfo::CloseDeviceInterface(void)
00288 {
00289 if (!fw_handle)
00290 return;
00291
00292 (*fw_handle)->RemoveCallbackDispatcherFromRunLoop(fw_handle);
00293 (*fw_handle)->Close(fw_handle);
00294 (*fw_handle)->Release(fw_handle);
00295
00296 fw_handle = NULL;
00297 }
00298
00299 bool DarwinAVCInfo::GetDeviceNodes(int &local_node, int &remote_node)
00300 {
00301 uint32_t generation = 0;
00302 uint16_t node = 0;
00303 local_node = -1;
00304 remote_node = -1;
00305
00306 if ((*fw_handle)->version < 4)
00307 {
00308 if (kIOReturnSuccess == (*fw_handle)->GetGenerationAndNodeID(
00309 fw_handle, (UInt32*) &generation, (UInt16*) &node))
00310 {
00311 remote_node = node;
00312 }
00313
00314 if (kIOReturnSuccess == (*fw_handle)->GetLocalNodeID(
00315 fw_handle, (UInt16*) &node))
00316 {
00317 local_node = node;
00318 }
00319 }
00320
00321 int ret = (*fw_handle)->GetBusGeneration(fw_handle, (UInt32*)&generation);
00322 if (kIOReturnSuccess == ret)
00323 {
00324 if (kIOReturnSuccess == (*fw_handle)->GetLocalNodeIDWithGeneration(
00325 fw_handle, generation, (UInt16*) &node))
00326 {
00327 local_node = node;
00328 }
00329
00330 if (kIOReturnSuccess == (*fw_handle)->GetRemoteNodeID(
00331 fw_handle, generation, (UInt16*) &node))
00332 {
00333 remote_node = node;
00334 }
00335 }
00336
00337 return (local_node >= 0) && (remote_node >= 0);
00338 }
00339
00340 static void dfd_device_change_msg(
00341 void *dfd, io_service_t, natural_t messageType, void*)
00342 {
00343 DarwinFirewireDevice *dev = (DarwinFirewireDevice*) dfd;
00344 dev->HandleDeviceChange(messageType);
00345 }