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/*
24 cc -framework QuickTime -I/System/Library/Extensions/IOFWDV.kext/Headers -I/System/Library/Frameworks/QuickTime.framework/Headers -I/System/Library/Frameworks/Carbon.framework/Headers testcomp.c /System/Library/Extensions/IOFWDV.kext/libIOFWDV.a -o testcomp
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <iokit/IOKitLib.h>
34
35//#define TARGET_CARBON 1
36#include <Carbon/Carbon.h>
37
38//#include <Carbon/MacMemory.h>
39//#include <Carbon/Components.h>
40
41#include "IsochronousDataHandler.h"
42#include "DeviceControl.h"
43
44static int done = 0;
45static int file = 0;
46static     QTAtomSpec videoConfig;
47
48static void printP(const char *s)
49{
50    int len = *s++;
51    while(len--)
52        printf("%c", *s++);
53}
54
55static void print4(const char *s, UInt32 val)
56{
57    printf("%s'%c%c%c%c'(0x%x)", s, val>>24, val>>16, val>>8, val, val);
58}
59
60// called when a new isoch read is received
61static OSStatus DVIsochComponentReadCallback( IDHGenericEvent *eventRecord, void *userData)
62{
63        OSErr 					result = noErr;
64        IDHParameterBlock		*pb = (IDHParameterBlock *) eventRecord;
65
66#if 1
67        ComponentInstance	theInst = userData;
68
69        if(file)
70            write(file, pb->buffer, pb->actualCount);
71
72        result = IDHReleaseBuffer( theInst, pb);
73        // fill out structure
74        pb->buffer 			= NULL;
75        pb->requestedCount	= 120000;
76        pb->actualCount 	= 0;
77        pb->completionProc 	= DVIsochComponentReadCallback;
78        // do another read
79        result = IDHRead( theInst, pb);
80        if( result != noErr) {
81            printf("IDHRead error %d\n", result);
82        }
83#else
84        printf("read complete for block 0x%x, refcon 0x%x\n", pb, userData);
85#endif
86        done++;
87        return result;
88}
89
90// called when a new isoch read is received
91static OSStatus DVIsochComponentWriteCallback( IDHGenericEvent *eventRecord, void *userData)
92{
93        OSErr 					result = noErr;
94        IDHParameterBlock		*pb = (IDHParameterBlock *) eventRecord;
95
96#if 1
97        ComponentInstance	theInst = userData;
98
99        if(file) {
100            int len;
101            len = read(file, pb->buffer, 120000);
102            if(len < 120000)
103                return result;
104        }
105#if WRITEBUFF
106#else
107        pb->buffer = nil;
108#endif
109        // fill out structure
110        pb->requestedCount	= 120000;
111        pb->actualCount 	= 0;
112        pb->completionProc 	= DVIsochComponentWriteCallback;
113        // do another write
114        result = IDHWrite( theInst, pb);
115        if( result != noErr) {
116            printf("IDHWrite error %d\n", result);
117        }
118#else
119        printf("write complete for block 0x%x, refcon 0x%x\n", pb, userData);
120#endif
121        done++;
122        return result;
123}
124
125static void doControlTest(ComponentInstance theInst, QTAtomSpec *currentIsochConfig)
126{
127        //Component control;
128        ComponentInstance controlInst;
129        ComponentResult result;
130        IDHDeviceStatus			devStatus;
131        DVCTransactionParams 	pParams;
132        char					in[4], out[16];
133        int i;
134
135        result = IDHGetDeviceControl(theInst, &controlInst);
136        if(result)
137                goto Exit;
138        //controlInst = OpenComponent(control);
139        // get the local node's fw ref id
140        result = IDHGetDeviceStatus( theInst, currentIsochConfig, &devStatus);
141        if(result)
142                goto Exit;
143        //result = FWClockPrivSetFWReferenceID(clockInst, (FWReferenceID) devStatus.localNodeID );
144        //if(result)
145        //	goto Exit;
146
147        // set the clock's fw id
148        //clockInst = OpenDefaultComponent(clockComponentType, systemMicrosecondClock);
149
150        if(!controlInst)
151                goto Exit;
152
153
154        // fill up the avc frame
155        in[0]	= 0x00; //kAVCControlCommand;
156        in[1] 	= 0x20;						// for now
157        in[2] 	= 0xc3; //kAVCPlayOpcode;
158        in[3] 	= 0x75; //kAVCPlayForward;
159
160        // fill up the transaction parameter block
161    pParams.commandBufferPtr = in;
162    pParams.commandLength = sizeof(in);
163    pParams.responseBufferPtr = out;
164    pParams.responseBufferSize = sizeof(out);
165    pParams.responseHandler = NULL;
166
167    do {
168        for(i=0; i<sizeof(out); i++)
169                out[i] = 0;
170        result = DeviceControlDoAVCTransaction( controlInst, &pParams);
171        if(result == kIOReturnOffline) {
172            printf("offline!!\n");
173            sleep(1);
174            continue;
175        }
176        if(result)
177            goto Exit;
178        printf("Received %d bytes:", pParams.responseBufferSize);
179        for(i=0; i<sizeof(out); i++)
180                printf("%d(0x%x) ", out[i], out[i]);
181        printf("\n");
182    } while(result != kIOReturnSuccess);
183
184    //sleep(10);
185    CallComponentClose(controlInst, 0);
186
187Exit:
188        if(result != noErr)
189                printf("Control error %d(%x)\n", result, result);
190}
191
192static OSErr doReadTest(ComponentInstance theInst)
193{
194    Ptr myBuffer;
195    IDHParameterBlock isochParamBlock;
196    OSErr err;
197
198    // open the DV device for reading
199    err = IDHOpenDevice( theInst, kIDHOpenForReadTransactions);
200    if( err != noErr)
201            goto error;
202
203    printf("Opened device\n");
204    doControlTest(theInst, &videoConfig);
205
206    file = open("/tmp/dump.rawdv", O_CREAT | O_WRONLY | O_TRUNC, 0666);
207#if 0
208    {
209        int i;
210        // we are doing isoch reads with only one buffer at a time
211        //myBuffer = NewPtrClear(120000);
212
213        for(i=0; i<1000; i++) {
214
215           // isochParamBlock.buffer 		= myBuffer;
216            isochParamBlock.buffer 		= nil;
217            isochParamBlock.requestedCount	= 120000;	// NTSC buffer size
218            isochParamBlock.actualCount 	= 0;
219            isochParamBlock.refCon		= (void *)0x12345678;
220
221
222            isochParamBlock.completionProc 	= 0;
223
224            err = IDHRead( theInst, &isochParamBlock);
225            if( err != noErr)
226                    goto error;
227            write(file, isochParamBlock.buffer, 120000);
228            err = IDHReleaseBuffer( theInst, &isochParamBlock);
229            if( err != noErr)
230                    goto error;
231        }
232
233    }
234#else
235    isochParamBlock.buffer 		= nil;
236    isochParamBlock.requestedCount	= 120000;	// NTSC buffer size
237    isochParamBlock.actualCount 	= 0;
238    isochParamBlock.refCon		= (void *)theInst;
239
240
241    isochParamBlock.completionProc 	= DVIsochComponentReadCallback;
242
243    err = IDHRead( theInst, &isochParamBlock);
244    if( err != noErr)
245            goto error;
246    printf("Issued read\n");
247
248    while(!done)
249            sleep(1);
250    sleep(10);
251    printf("Did %d frames\n", done);
252//    err = IDHReleaseBuffer( theInst, &isochParamBlock);
253#endif
254    // close the DV device
255    err = IDHCloseDevice( theInst);
256    if( err != noErr)
257            goto error;
258
259    printf("Closed device\n");
260
261    printf("Read %d bytes\n", isochParamBlock.actualCount);
262    if(isochParamBlock.actualCount)
263    {
264            int i,j;
265            UInt8 *p = (UInt8 *)isochParamBlock.buffer;
266            for(i=0; i<100; i++) {
267                    printf("%d: ", i*40);
268                    for(j=0; j<40; j++)
269                            printf("%2x ",*p++);
270                    printf("\n");
271            }
272    }
273error:
274    return err;
275}
276
277static OSErr doWriteTest(ComponentInstance theInst)
278{
279    Ptr myBuffer;
280    IDHParameterBlock isochParamBlock;
281    OSErr err;
282
283    // open the DV device for writing
284    err = IDHOpenDevice( theInst, kIDHOpenForWriteTransactions);
285    if( err != noErr)
286            goto error;
287
288    printf("Opened device\n");
289
290    myBuffer = NewPtrClear(120000);
291    file = open("/work/dinosaur.rawdv", O_RDONLY, 0666);
292    printf("open file: %d\n", file);
293#if 0
294    {
295        int i;
296        // we are doing isoch reads with only one buffer at a time
297
298        for(i=0; i<1000; i++) {
299            file = open("/work/dinosaur.rawdv", O_RDONLY, 0666);
300            printf("open file: %d\n", file);
301            while(true) {
302                int len;
303                len = read(file, myBuffer, 120000);
304                if(len < 120000)
305                    break;
306                isochParamBlock.buffer 		= myBuffer;
307                //isochParamBlock.buffer 		= nil;
308                isochParamBlock.requestedCount	= 120000;	// NTSC buffer size
309                isochParamBlock.actualCount 	= 0;
310                isochParamBlock.refCon		= (void *)0x12345678;
311
312                isochParamBlock.completionProc 	= 0;
313
314                err = IDHWrite( theInst, &isochParamBlock);
315                if( err != noErr)
316                        goto error;
317            }
318            close(file);
319            file = open("/work/dinosaur.rawdv", O_RDONLY, 0666);
320            printf("open file: %d\n", file);
321        }
322    }
323#else
324#if WRITEBUFF
325    read(file, myBuffer, 120000);
326    isochParamBlock.buffer 		= myBuffer;
327#else
328    isochParamBlock.buffer 		= nil;
329#endif
330    isochParamBlock.requestedCount	= 120000;	// NTSC buffer size
331    isochParamBlock.actualCount 	= 0;
332    isochParamBlock.refCon		= (void *)theInst;
333
334
335    isochParamBlock.completionProc 	= DVIsochComponentWriteCallback;
336
337    err = IDHWrite( theInst, &isochParamBlock);
338    if( err != noErr)
339            goto error;
340    printf("Issued write\n");
341
342    while(!done)
343            sleep(1);
344    sleep(100);
345    printf("Did %d frames\n", done);
346#endif
347    // close the DV device
348    err = IDHCloseDevice( theInst);
349    if( err != noErr)
350            goto error;
351
352    printf("Closed device\n");
353
354error:
355    return err;
356}
357
358
359static void OpenDV()
360{
361    ComponentInstance theInst;
362    ComponentResult version;
363    QTAtomContainer deviceList = NULL;
364    short nDVDevices, i, j;
365    QTAtom deviceAtom;
366    UInt32 cmpFlag;
367    UInt32 isoversion;
368    long size;
369    OSErr err;
370
371    theInst = OpenDefaultComponent('ihlr', 'dv  ');
372    printf("Instance is 0x%x\n", theInst);
373        if(theInst == NULL)
374                return;
375
376    version = CallComponentVersion(theInst);
377    printf("Version is 0x%x\n", version);
378
379    do {
380        err = IDHGetDeviceList( theInst, &deviceList);
381        if( err != noErr)
382                goto error;
383
384        nDVDevices = QTCountChildrenOfType( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType);
385        if(nDVDevices > 0)
386            break;
387        sleep(1);
388    } while(true);
389
390
391    QTLockContainer( deviceList);
392    // find the cmp atom
393    deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil);
394    if( deviceAtom == nil)
395            goto error;
396
397    // get the value of the cmp atom
398    QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( cmpFlag), &cmpFlag, &size);
399
400    // find the version atom
401    deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHIsochVersionAtomType, 1, nil);
402    if( deviceAtom == nil)
403            goto error;
404
405    // get the value of the version atom
406    QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( isoversion), &isoversion, &size);
407
408    printf("Version 0x%x. %d DV devices, use CMP flag is %d\n", isoversion, nDVDevices, cmpFlag);
409
410    for( i=0; i<nDVDevices; ++i)
411    {
412            QTAtom isochAtom, dataAtom;
413            UInt32 test[2];
414            int nConfigs;
415            char cameraName[256];
416            IDHDeviceID deviceID;
417            IDHDeviceStatus deviceStatus;
418
419            // get the atom to this device
420            deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType, i + 1, nil);
421            if( deviceAtom == nil)
422                    goto error;
423
424            printf("device %d ", i);
425
426            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHUniqueIDType, 1, nil);
427            if( dataAtom == nil)
428                    goto error;
429            QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( test), test, &size);
430            printf("guid 0x%x%08x ", test[0], test[1]);
431
432            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHNameAtomType, 1, nil);
433            if( dataAtom == nil)
434                    goto error;
435            QTCopyAtomDataToPtr( deviceList, dataAtom, true, 255, cameraName, &size);
436            cameraName[size] = 0;
437            printf("%s ", cameraName+1);
438
439            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHDeviceIDType, 1, nil);
440            if( dataAtom == nil)
441                    goto error;
442            QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceID), &deviceID, &size);
443            printf("deviceID 0x%x ", deviceID);
444
445            dataAtom = QTFindChildByIndex( deviceList, deviceAtom, 'ddin', 1, nil);
446            if( dataAtom == nil)
447                    goto error;
448            QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceStatus), &deviceStatus, &size);
449            printf("\ndevice status:\n");
450            printf("version %d\n", deviceStatus.version);
451            printf("physicallyConnected %d\n", deviceStatus.physicallyConnected);
452            printf("readEnabled %d ", deviceStatus.readEnabled);
453            printf("writeEnabled %d ", deviceStatus.writeEnabled);
454            printf("exclusiveAccess %d\n", deviceStatus.exclusiveAccess);
455            printf("currentBandwidth %d ", deviceStatus.currentBandwidth);
456            printf("currentChannel %d ", deviceStatus.currentChannel);
457            printf("inputStandard %d ", deviceStatus.inputStandard);
458            printf("deviceActive %d\n", deviceStatus.deviceActive);
459
460            // find the isoch characteristics for this device
461            isochAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHIsochServiceAtomType, 1, nil);
462            if( isochAtom == nil)
463                    goto error;
464
465            // how many configs exist for this device
466            nConfigs = QTCountChildrenOfType( deviceList, isochAtom, kIDHIsochModeAtomType);
467            printf("\n%d configs:\n", nConfigs);
468
469            videoConfig.atom = nil;	// start with no selected config
470
471            // process each config
472            for( j=0; j<nConfigs; ++j)
473            {
474                    OSType mediaType;
475                    QTAtom configAtom, mediaAtom;
476
477                    // get this configs atom
478                    configAtom = QTFindChildByIndex( deviceList, isochAtom, kIDHIsochModeAtomType, j + 1, nil);
479                    if( configAtom == nil)
480                            goto error;
481
482                    printf("Config %d",j);
483                    // find the media type atom
484                    mediaAtom = QTFindChildByIndex( deviceList, configAtom, kIDHIsochMediaType, 1, nil);
485                    if( mediaAtom == nil)
486                            goto error;
487
488                    // get the value of the mediaType atom
489                    QTCopyAtomDataToPtr( deviceList, mediaAtom, true, sizeof( mediaType), &mediaType, &size);
490                    print4(" Media type:", mediaType);
491
492                    // is this config an video config?
493                    if( mediaType == kIDHVideoMediaAtomType)	// found video device
494                    {
495                            videoConfig.container = deviceList;	// save this config
496                            videoConfig.atom = configAtom;
497                            //break;
498                    }
499                    printf("\n");
500            }
501            printf("-----\n");
502
503    }
504
505    if( videoConfig.atom == nil)	// no good configs found
506            goto error;
507
508    QTUnlockContainer( deviceList);
509    deviceList = NULL;
510
511    printf("setting config\n");
512    // set isoch to use this config
513    err = IDHSetDeviceConfiguration( theInst, &videoConfig);
514    if( err != noErr)
515            goto error;
516
517#if 1
518    err = doReadTest(theInst);
519#else
520    err = doWriteTest(theInst);
521#endif
522    if( err != noErr)
523            goto error;
524
525error:
526    if( err != noErr)
527        printf("error %d(0x%x)\n", err, err);
528    if(deviceList) {
529            QTUnlockContainer( deviceList);
530    }
531
532    CallComponentClose(theInst, 0);
533
534}
535
536
537int main(void)
538{
539	UInt32 seed = GetComponentListModSeed();
540	UInt32 num;
541	Handle aName;
542	ComponentDescription desc, aDesc;
543	Component aComponent;
544        ComponentInstance theInst;
545        ComponentResult version;
546
547	printf("Component seed is %d\n", seed);
548	desc.componentType = 0;				/* A unique 4-byte code indentifying the command set */
549        //desc.componentType = 'ihlr';				/* A unique 4-byte code indentifying the command set */
550	desc.componentSubType = 0;			/* Particular flavor of this instance */
551	desc.componentManufacturer = 0;		/* Vendor indentification */
552	desc.componentFlags = 0;				/* 8 each for Component,Type,SubType,Manuf/revision */
553	desc.componentFlagsMask = 0;			/* Mask for specifying which flags to consider in search, zero during registration */
554
555	num = CountComponents(&desc);
556	printf("%d components match\n", num);
557
558	aComponent = 0;
559	aName = NewHandleClear(200);
560	while (aComponent = FindNextComponent(aComponent, &desc)) {
561		OSErr oops;
562		printf("Found component 0x%x:", aComponent);
563		oops = GetComponentInfo(aComponent, &aDesc, aName,
564                                         NULL, NULL);
565        if(oops)
566        	printf("GetComponentInfo() returned error %d\n", oops);
567        else {
568        	if(GetHandleSize(aName))
569        		printP(*aName);
570        	else
571        		printf("Unnamed");
572                print4(", Type ", aDesc.componentType);
573
574                print4(", SubType ", aDesc.componentSubType);
575                print4(", Manufacturer ", aDesc.componentManufacturer);
576                printf("\n");
577	}
578        }
579
580	OpenDV();
581	return 0;
582}
583
584