1/*
2 * Copyright (c) 2000 Apple Computer, 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 -fno-rtti -fno-exceptions -fcheck-new -fvtable-thunks -arch ppc -lIOKit FireWireTest.cpp -o FireWireTest
25
26 cc -fno-rtti -fno-exceptions -fcheck-new -fvtable-thunks -I.. -I../../BUILD/obj/EXPORT_HDRS/libkern -I../../BUILD/obj/EXPORT_HDRS/osfmk FireWireTest.cpp ../../BUILD/obj/RELEASE_PPC/iokit/User/libIOKit.A.dylib -o FireWireTest
27
28*/
29
30extern "C" {
31#include <mach/message.h>
32}
33
34#include <IOKit/IOLib.h>
35#include <IOKit/IOKitLib.h>
36#include <IOKit/IOContainers.h>
37#include <IOKit/IOSerialize.h>
38
39extern "C" {
40#include "../../BUILD/obj/RELEASE_PPC/iokit/User/DeviceUser.h"
41    extern mach_port_t bootstrap_port;
42}
43
44#include <ctype.h>
45#include <stdlib.h>
46#include <stdio.h>
47
48// Temporary place for these
49enum {
50    kFireWireRead = 0,
51    kFireWireWrite,
52    kFireWireCompareSwap,
53    kFireWireBusReset,
54    kFireWireTest,
55    kNumFireWireMethods
56};
57
58mach_port_t	master_device_port;
59io_connect_t	connection;
60bool dotest, domap, doread, dowrite, dolock, doforever, dobusreset;
61
62UInt32 addrHi, addrLo;
63int tranSize;
64
65IOReturn doTest()
66{
67    IOReturn kr;
68    int args[4];
69    unsigned int size;
70    size = 0;
71    kr = io_connect_method_scalarI_scalarO( connection, kFireWireTest,
72            args, 0, NULL, &size);
73    if(kIOReturnSuccess != kr)
74        printf("Test returned 0x%x, size = %d:\n", kr, size);
75    return kr;
76}
77
78IOReturn doMapMem()
79{
80    IOReturn		kr;
81    vm_size_t		shmemSize;
82    vm_address_t	bufMem;
83
84    kr = IOMapMemory( connection, addrLo, mach_task_self(),
85                        &bufMem, &shmemSize, TRUE);
86    if(kIOReturnSuccess == kr) {
87        int i;
88        printf("mapped %d bytes at 0x%x\n", shmemSize, bufMem);
89        for(i=0; i<shmemSize/4; i++)
90            *(int *)(bufMem+i*sizeof(int)) = i;
91    }
92    return kr;
93}
94
95void runTests(io_object_t device)
96{
97    IOReturn kr;
98    unsigned int size;
99    int i;
100    int args[4];
101    char buf[4096];
102    kr = IOServiceOpen(device, mach_task_self(), 11, &connection);
103    if(kIOReturnSuccess != kr) {
104        printf("IOServiceOpen failed: 0x%x\n", kr);
105	return;
106    }
107
108    if(domap) {
109    // Now map some memory for it.
110        kr = doMapMem();
111        if(kIOReturnSuccess != kr)
112            return;
113    }
114    if(doread) {
115        args[0] = addrHi; // Addr Hi
116        args[1] = addrLo; // Addr Lo
117        size = tranSize;
118        kr = io_connect_method_scalarI_structureO( connection, kFireWireRead,
119                args, 2, buf, &size);
120        printf("Read of 0x%x:0x%x returned 0x%x, size = %d: ", args[0], args[1], kr, size);
121        for(i=0; i<size/4; i++)
122            printf("0x%x ", *((UInt32 *)buf + i));
123        printf("\n");
124    }
125    do {
126        if(dobusreset) {
127            size = 0;
128            kr = io_connect_method_scalarI_scalarO(connection,
129		kFireWireBusReset, args, 0, args, &size);
130            if(kIOReturnSuccess != kr)
131                printf("Bus reset returned 0x%x: ", kr);
132        }
133
134	if(dowrite) {
135            size = tranSize;
136            for(i=0; i<size/4; i++)
137                *( (UInt32 *)buf+i) += 0x01010101;
138            args[0] = addrHi; // Addr Hi
139            args[1] = addrLo; // Addr Lo
140            kr = io_connect_method_scalarI_structureI(connection, kFireWireWrite,
141                    args, 2, buf, size);
142            if(kIOReturnSuccess != kr)
143                printf("Write returned 0x%x, size = %d:\n", kr, size);
144	}
145	if(dolock) {
146            args[0] = addrHi; // Addr Hi
147            args[1] = addrLo; // Addr Lo
148            args[2] = ((UInt32 *)buf)[0];
149            args[3] = ((UInt32 *)buf)[1];
150            size = 0;
151            kr = io_connect_method_scalarI_scalarO( connection, kFireWireCompareSwap,
152                    args, 4, NULL, &size);
153            if(kIOReturnSuccess != kr) {
154                printf("Compare&Swap returned 0x%x\n", kr);
155                break;
156            }
157        }
158        if(doread) {
159            args[0] = addrHi; // Addr Hi
160            args[1] = addrLo; // Addr Lo
161            size = tranSize;
162            kr = io_connect_method_scalarI_structureO( connection, kFireWireRead,
163                    args, 2, buf, &size);
164            printf("Read of 0x%x:0x%x returned 0x%x, size = %d: ", args[0], args[1], kr, size);
165            if(kIOReturnSuccess != kr)
166		break;
167            for(i=0; i<size/4; i++)
168                printf("0x%x ", *((UInt32 *)buf + i));
169            printf("\n");
170        }
171        if(dotest)
172            kr = doTest();
173
174    } while(doforever && kIOReturnSuccess == kr);
175
176}
177
178kern_return_t processDevice(io_object_t device, UInt64 guid)
179{
180    kern_return_t	kr;
181    IOObject *		object;
182    IODictionary *	properties;
183    IOOffset *		dataDesc;
184    UInt32		nodeID;
185    UInt64		gotGUID;
186
187    kr = IORegistryEntryGetProperties(device, &object);
188    if (kr)
189        return kr;
190    if(!object)
191        return kIOReturnBadArgument;
192
193    properties = (IODictionary *)object;
194    dataDesc = (IOOffset *)properties->getObject("FireWire Node ID");
195    if(0 == dataDesc)
196        return kIOReturnBadArgument;
197    nodeID = dataDesc->unsigned32BitValue();
198    dataDesc = (IOOffset *)properties->getObject("GUID");
199    if(0 == dataDesc)
200        return kIOReturnBadArgument;
201    gotGUID = dataDesc->unsigned64BitValue();
202    dataDesc = (IOOffset *)properties->getObject("Unit_Spec_ID");
203    if(0 != dataDesc) {
204        printf("Found device %x, Unit_Spec_ID: 0x%x, GUID: 0x%x:0x%x\n", nodeID, dataDesc->unsigned32BitValue(),
205		(UInt32)(gotGUID>>32), (UInt32)(gotGUID & 0xffffffff));
206    }
207    else {
208        printf("Found device %x with no units, GUID: 0x%x:0x%x\n", nodeID,
209			(UInt32)(gotGUID>>32), (UInt32)(gotGUID & 0xffffffff));
210    }
211    object->release();
212    if(guid == gotGUID) {
213	printf("Found it!\n");
214        runTests(device);
215        exit(0);
216    }
217    return kIOReturnSuccess;
218}
219
220int pokeDevices(UInt64 guid)
221{
222    kern_return_t	kr;
223    io_iterator_t	enumer;
224    io_object_t		obj;
225    mach_port_t		port;
226    unsigned long int  	notifyType;
227    unsigned long int  	ref;
228    struct {
229        mach_msg_header_t	msgHdr;
230        OSNotificationHeader	notifyHeader;
231        mach_msg_trailer_t	trailer;
232    } msg;
233
234    kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
235    if(KERN_SUCCESS != kr) {
236        printf("Failed to create port!:%d\n", kr);
237        return kr;
238    }
239
240    kr = IOServiceAddNotification( master_device_port, kIOMatchedNotification,
241                                    IOServiceMatching( "IOFireWireDevice" ),
242                                    port, 12345, &enumer );
243
244    if(kIOReturnSuccess != kr) {
245        printf("IOServiceAddNotification = %d\n", kr);
246        return kr;
247    }
248
249    // First process any devices already connected
250    while(obj = IOIteratorNext(enumer)) {
251        processDevice(obj, guid);
252    }
253
254    // Now wait for a new device (or devices) to appear and
255    // process them.
256    kr = mach_msg(&msg.msgHdr, MACH_RCV_MSG,
257                0, sizeof(msg), port, 0, MACH_PORT_NULL);
258    kr = OSGetNotificationFromMessage( &msg.msgHdr, 0, &notifyType, &ref,
259                    0, 0 );
260
261    if(ref == 12345) {
262        while(obj = IOIteratorNext(enumer)) {
263            processDevice(obj, guid);
264        }
265    }
266    else
267        printf("Unexpected notification type %d, ref %d\n",
268		notifyType, ref);
269    IOObjectRelease( enumer);
270    return kr;
271}
272
273int
274main(int argc, char **argv)
275{
276    kern_return_t	kr;
277    UInt64 guid = 0;
278
279    IOString *grr;
280    grr = new IOString;
281    grr->release();
282
283    /*
284     * Get master device port
285     */
286    kr = IOMasterPort(bootstrap_port,
287                              &master_device_port);
288
289    if (kr != KERN_SUCCESS)
290        printf("IOMasterPort failed: %lx\n", kr);
291    tranSize = 32;
292    addrHi = 0xffff;
293    addrLo = 0xf0000400;
294    if(argc > 1) {
295        if(strrchr(argv[1], 'h')) {
296            printf("%s guid [t/m/r/w/l/b/f] [size] [addrHi] [addrLo]\n", argv[0]);
297            printf("t=test, m=map memory, r=read, w=write, l=lock, b=busreset, f=repeat forever\n");
298            printf("size defaults to %d, addrHi to 0x%x, addrLo to 0x%x (config ROM)\n",
299		tranSize, addrHi, addrLo);
300            exit(0);
301        }
302        guid = strtoq(argv[1], NULL, 0);
303    }
304    if(argc > 2) {
305        dotest = strrchr(argv[2], 't');
306        domap = strrchr(argv[2], 'm');
307        doread = strrchr(argv[2], 'r');
308        dowrite = strrchr(argv[2], 'w');
309        dolock = strrchr(argv[2], 'l');
310        dobusreset = strrchr(argv[2], 'b');
311        doforever = strrchr(argv[2], 'f');
312    }
313    if(argc > 3)
314        tranSize = strtol(argv[3], NULL, 0);
315    if(argc > 4)
316        addrHi = strtol(argv[4], NULL, 0);
317    if(argc > 5)
318        addrLo = (UInt32)strtoq(argv[5], NULL, 0);
319    pokeDevices(guid);
320}
321
322