1/*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <Carbon/Carbon.h>
24#include <QuickTime/QuickTime.h>
25
26#include <stdio.h>
27#include <stdlib.h>
28
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <iokit/IOKitLib.h>
33#include <iokit/avc/IOFireWireAVCConsts.h>
34
35#include <DVComponentGlue/IsochronousDataHandler.h>
36#include <DVComponentGlue/DeviceControl.h>
37
38static QTAtomSpec videoConfig;
39static IDHDeviceID deviceID;
40static IDHNotificationID notificationID;
41
42static void printP(const char *s)
43{
44    int len = *s++;
45    while(len--)
46        printf("%c", *s++);
47}
48
49static void print4(const char *s, UInt32 val)
50{
51    printf("%s'%c%c%c%c'(0x%x)", s, val>>24, val>>16, val>>8, val, val);
52}
53
54static OSStatus notificationProc(IDHGenericEvent* event, void* userData)
55{
56    ComponentInstance	theInst = userData;
57    printf("Got notification for device 0x%x, notification 0x%x, event 0x%x, userdata 0x%x\n",
58        event->eventHeader.deviceID, event->eventHeader.notificationID, event->eventHeader.event,
59        userData);
60
61        // Reenable notification
62   IDHNotifyMeWhen(theInst, event->eventHeader.notificationID, kIDHEventEveryEvent);
63
64    return noErr;
65}
66
67static void doControlTest(ComponentInstance theInst, QTAtomSpec *currentIsochConfig, UInt8 op1, UInt8 op2)
68{
69        //Component control;
70        ComponentInstance controlInst;
71        ComponentResult result;
72        IDHDeviceStatus			devStatus;
73        DVCTransactionParams 	pParams;
74        char					in[4], out[16];
75        //char					in[44], out[44];
76        int i;
77
78        result = IDHGetDeviceControl(theInst, &controlInst);
79        if(result)
80                goto Exit;
81        //controlInst = OpenComponent(control);
82        // get the local node's fw ref id
83        result = IDHGetDeviceStatus( theInst, currentIsochConfig, &devStatus);
84        if(result)
85                goto Exit;
86        //result = FWClockPrivSetFWReferenceID(clockInst, (FWReferenceID) devStatus.localNodeID );
87        //if(result)
88        //	goto Exit;
89
90        // set the clock's fw id
91        //clockInst = OpenDefaultComponent(clockComponentType, systemMicrosecondClock);
92
93        if(!controlInst)
94                goto Exit;
95
96#if 1
97        // fill up the avc frame
98        in[0]	= kAVCStatusInquiryCommand; //kAVCControlCommand;
99        in[1] 	= 0x20;						// for now
100        in[2] 	= op1;
101        in[3] 	= op2;
102#else
103        // fill up the avc frame
104        in[0]	= 0x00;
105        in[1] 	= 0x58;						// for now
106        in[2] 	= 0x50;
107        in[3] 	= 0x00;
108
109        in[4]	= 0xff;
110        in[5] 	= 0x00;						// for now
111        in[6] 	= 0x00;
112        in[7] 	= 0x00;
113
114        in[8]	= 0xff;
115        in[9]	= 0xff;
116        in[10]	= 0xff;
117        in[11]	= 0xff;
118
119        in[12] 	= 0x00;
120        in[13] 	= 0x00;
121        in[14] 	= 0x00;
122        in[15] 	= 0x1b;
123
124        in[16] 	= 0x5c;
125        in[17] 	= 0x44;
126        in[18] 	= 0x43;
127        in[19] 	= 0x49;
128
129        in[20] 	= 0x4d;
130        in[21] 	= 0x5c;
131        in[22] 	= 0x31;
132        in[23] 	= 0x30;
133
134        in[24] 	= 0x31;
135        in[25] 	= 0x43;
136        in[26] 	= 0x41;
137        in[27] 	= 0x4e;
138
139        in[28] 	= 0x4f;
140        in[29] 	= 0x4e;
141        in[30] 	= 0x5c;
142        in[31] 	= 0x41;
143
144        in[32] 	= 0x55;
145        in[33] 	= 0x54;
146        in[34] 	= 0x5f;
147        in[35] 	= 0x30;
148
149        in[36] 	= 0x31;
150        in[37] 	= 0x30;
151        in[38] 	= 0x33;
152        in[39] 	= 0x2e;
153
154        in[40] 	= 0x4a;
155        in[41] 	= 0x50;
156        in[42] 	= 0x47;
157        in[43] 	= 0x00;
158
159
160#endif
161
162        // fill up the transaction parameter block
163    pParams.commandBufferPtr = in;
164    pParams.commandLength = sizeof(in);
165    pParams.responseBufferPtr = out;
166    pParams.responseBufferSize = sizeof(out);
167    pParams.responseHandler = NULL;
168
169    do {
170        for(i=0; i<sizeof(out); i++)
171                out[i] = 0;
172        result = DeviceControlDoAVCTransaction( controlInst, &pParams);
173        if(result == kIOReturnOffline) {
174            printf("offline!!\n");
175            sleep(1);
176            continue;
177        }
178        if(result)
179            goto Exit;
180        printf("Received %d bytes:", pParams.responseBufferSize);
181        for(i=0; i<sizeof(out); i++)
182                printf("%d(0x%x) ", out[i], out[i]);
183        printf("\n");
184    } while (1); //(result != kIOReturnSuccess);
185
186    //sleep(10);
187
188Exit:
189        if(result != noErr)
190                printf("Control error %d(%x)\n", result, result);
191}
192
193static void OpenDV()
194{
195    ComponentInstance theInst;
196    ComponentResult version;
197    QTAtomContainer deviceList = NULL;
198    short nDVDevices, i, j;
199    QTAtom deviceAtom;
200    UInt32 cmpFlag;
201    UInt32 isoversion;
202    long size;
203    OSStatus err;
204
205    theInst = OpenDefaultComponent('ihlr', 'dv  ');
206    printf("Instance is 0x%x\n", theInst);
207        if(theInst == NULL)
208                return;
209
210    version = CallComponentVersion(theInst);
211    printf("Version is 0x%x\n", version);
212
213// Ask for notifications for what's happening - ask for EVERYTHING!!
214    err = IDHNewNotification(theInst, kIDHDeviceIDEveryDevice, notificationProc, theInst, &notificationID);
215    if( err != noErr)
216            goto error;
217
218    err = IDHNotifyMeWhen(theInst, notificationID, kIDHEventEveryEvent);
219    if( err != noErr)
220            goto error;
221
222    do {
223        err = IDHGetDeviceList( theInst, &deviceList);
224        if( err != noErr)
225                goto error;
226
227        nDVDevices = QTCountChildrenOfType( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType);
228        if(nDVDevices > 0)
229            break;
230        printf("Waiting for a camera...\n");
231        sleep(1);
232    } while(true);
233
234
235    QTLockContainer( deviceList);
236    // find the cmp atom
237    deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil);
238    if( deviceAtom == nil)
239            goto error;
240
241    // get the value of the cmp atom
242    QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( cmpFlag), &cmpFlag, &size);
243
244    // find the version atom
245    deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHIsochVersionAtomType, 1, nil);
246    if( deviceAtom == nil)
247            goto error;
248
249    // get the value of the version atom
250    QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( isoversion), &isoversion, &size);
251
252    printf("Version 0x%x. %d DV devices, use CMP flag is %d\n", isoversion, nDVDevices, cmpFlag);
253
254    for( i=0; i<nDVDevices; ++i)
255    {
256            QTAtom isochAtom, dataAtom;
257            UInt32 test[2];
258            int nConfigs;
259            char cameraName[256];
260            IDHDeviceStatus deviceStatus;
261
262            // get the atom to this device
263            deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType, i + 1, nil);
264            if( deviceAtom == nil)
265                    goto error;
266
267            printf("device %d ", i);
268
269            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHUniqueIDType, 1, nil);
270            if( dataAtom == nil)
271                    goto error;
272            QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( test), test, &size);
273            printf("guid 0x%x%08x ", test[0], test[1]);
274
275            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHNameAtomType, 1, nil);
276            if( dataAtom == nil)
277                    goto error;
278            QTCopyAtomDataToPtr( deviceList, dataAtom, true, 255, cameraName, &size);
279            cameraName[size] = 0;
280            printf("%s ", cameraName+1);
281
282            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHDeviceIDType, 1, nil);
283            if( dataAtom == nil)
284                    goto error;
285            QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceID), &deviceID, &size);
286            printf("deviceID 0x%x ", deviceID);
287
288            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, 'ddin', 1, nil);
289            if( dataAtom == nil)
290                    goto error;
291            QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceStatus), &deviceStatus, &size);
292            printf("\ndevice status:\n");
293            printf("version %d\n", deviceStatus.version);
294            printf("physicallyConnected %d\n", deviceStatus.physicallyConnected);
295            printf("readEnabled %d ", deviceStatus.readEnabled);
296            printf("writeEnabled %d ", deviceStatus.writeEnabled);
297            printf("exclusiveAccess %d\n", deviceStatus.exclusiveAccess);
298            printf("currentBandwidth %d ", deviceStatus.currentBandwidth);
299            printf("currentChannel %d ", deviceStatus.currentChannel);
300            printf("inputStandard %d ", deviceStatus.inputStandard);
301            printf("deviceActive %d\n", deviceStatus.deviceActive);
302
303            // find the isoch characteristics for this device
304            isochAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHIsochServiceAtomType, 1, nil);
305            if( isochAtom == nil)
306                    goto error;
307
308            // how many configs exist for this device
309            nConfigs = QTCountChildrenOfType( deviceList, isochAtom, kIDHIsochModeAtomType);
310            printf("\n%d configs:\n", nConfigs);
311
312            videoConfig.atom = nil;	// start with no selected config
313
314            // process each config
315            for( j=0; j<nConfigs; ++j)
316            {
317                    OSType mediaType;
318                    QTAtom configAtom, mediaAtom;
319
320                    // get this configs atom
321                    configAtom = QTFindChildByIndex( deviceList, isochAtom, kIDHIsochModeAtomType, j + 1, nil);
322                    if( configAtom == nil)
323                            goto error;
324
325                    printf("Config %d",j);
326                    // find the media type atom
327                    mediaAtom = QTFindChildByIndex( deviceList, configAtom, kIDHIsochMediaType, 1, nil);
328                    if( mediaAtom == nil)
329                            goto error;
330
331                    // get the value of the mediaType atom
332                    QTCopyAtomDataToPtr( deviceList, mediaAtom, true, sizeof( mediaType), &mediaType, &size);
333                    print4(" Media type:", mediaType);
334
335                    // is this config an video config?
336                    if( mediaType == kIDHVideoMediaAtomType)	// found video device
337                    {
338                            videoConfig.container = deviceList;	// save this config
339                            videoConfig.atom = configAtom;
340                            break;
341                    }
342                    printf("\n");
343            }
344            printf("-----\n");
345
346    }
347
348    if( videoConfig.atom == nil)	// no good configs found
349            goto error;
350
351    printf("setting config\n");
352    // set isoch to use this config
353    err = IDHSetDeviceConfiguration( theInst, &videoConfig);
354    if( err != noErr)
355            goto error;
356#if 1
357    doControlTest(theInst, &videoConfig,
358        //0xc3, //kAVCPlayOpcode
359        //0x75 //kAVCPlayForward
360        0xd0,	// Transport State
361        0x7f
362    );
363#else
364    {
365        TimeRecord time1, time2;
366        do {
367            err = IDHGetDeviceTime(theInst, &time1);
368            err = IDHGetDeviceTime(theInst, &time2);
369            if(time2.value.lo > time1.value.lo+1) {
370                //printf("read device time1, scale: %d, time 0x%x:0x%x\n",
371               //     time1.scale, time1.value.hi, time1.value.lo);
372                //printf("read device time2, scale: %d, time 0x%x:0x%x\n",
373                //    time2.scale, time2.value.hi, time2.value.lo);
374
375                printf("Diff is %d\n", time2.value.lo-time1.value.lo);
376            }
377        } while (1);
378    }
379#endif
380error:
381    if( err != noErr)
382        printf("error %d(0x%x)\n", err, err);
383    if(deviceList) {
384        QTUnlockContainer( deviceList);
385        QTDisposeAtomContainer(deviceList);
386    }
387
388    CloseComponent(theInst);
389
390}
391
392
393int main(int argc, char **argv)
394{
395	UInt32 seed = GetComponentListModSeed();
396	UInt32 num;
397	Handle aName;
398	ComponentDescription desc, aDesc;
399	Component aComponent;
400
401    int pos = 1;
402
403	printf("Component seed is %d\n", seed);
404        desc.componentType = 'ihlr';				/* A unique 4-byte code indentifying the command set */
405	desc.componentSubType = 0;			/* Particular flavor of this instance */
406	desc.componentManufacturer = 0;		/* Vendor indentification */
407	desc.componentFlags = 0;				/* 8 each for Component,Type,SubType,Manuf/revision */
408	desc.componentFlagsMask = 0;			/* Mask for specifying which flags to consider in search, zero during registration */
409
410	num = CountComponents(&desc);
411	printf("%d components match\n", num);
412
413	aComponent = 0;
414	aName = NewHandleClear(200);
415	while (aComponent = FindNextComponent(aComponent, &desc)) {
416		OSStatus oops;
417		printf("Found component 0x%x:", aComponent);
418		oops = GetComponentInfo(aComponent, &aDesc, aName,
419                                         NULL, NULL);
420        if(oops)
421        	printf("GetComponentInfo() returned error %d\n", oops);
422        else {
423        	if(GetHandleSize(aName))
424        		printP(*aName);
425        	else
426        		printf("Unnamed");
427                print4(", Type ", aDesc.componentType);
428
429                print4(", SubType ", aDesc.componentSubType);
430                print4(", Manufacturer ", aDesc.componentManufacturer);
431                printf("\n");
432	}
433        }
434
435    num = 0;
436    do {
437        ComponentInstance theInst;
438
439        theInst = OpenDefaultComponent('ihlr', 'dv  ');
440        //printf("Instance is 0x%x\n", theInst);
441        if(theInst == NULL)
442                return;
443        num++;
444        usleep(50000);
445        CloseComponent(theInst);
446    } while (0);
447	OpenDV();
448	return 0;
449}
450
451