2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * ci.c - Functions for accessing Open Firmware's Client Interface
28 * Copyright (c) 1998-2002 Apple Computer, Inc.
35 static ClientInterfacePtr gCIPtr
;
37 long InitCI(ClientInterfacePtr ciPtr
)
44 long CallCI(CIArgs
*ciArgsPtr
)
48 ret
= (*gCIPtr
)(ciArgsPtr
);
55 // Peer take a phandle and returns the next peer.
56 // It returns zero of there are no more peers.
57 CICell
Peer(CICell phandle
)
63 ciArgs
.service
= "peer";
66 ciArgs
.args
.peer
.phandle
= phandle
;
68 ret
= CallCI(&ciArgs
);
69 if (ret
!= 0) return kCIError
;
71 peer_ph
= ciArgs
.args
.peer
.peerPhandle
;
76 // Child take a phandle and returns the first child.
77 // It returns zero of there in no child.
78 CICell
Child(CICell phandle
)
84 ciArgs
.service
= "child";
87 ciArgs
.args
.child
.phandle
= phandle
;
89 ret
= CallCI(&ciArgs
);
90 if (ret
!= 0) return kCIError
;
92 child_ph
= ciArgs
.args
.child
.childPhandle
;
97 // Parent take a phandle and returns the parent node.
98 // It returns zero of if the phandle is the root node.
99 CICell
Parent(CICell phandle
)
105 ciArgs
.service
= "parent";
108 ciArgs
.args
.parent
.childPhandle
= phandle
;
110 ret
= CallCI(&ciArgs
);
111 if (ret
!= 0) return kCIError
;
113 parent_ph
= ciArgs
.args
.parent
.parentPhandle
;
118 // FindDevice take a device spec and returns the phandle.
119 // It returns zero of if the device was not found.
120 CICell
FindDevice(char *devSpec
)
126 ciArgs
.service
= "finddevice";
129 ciArgs
.args
.finddevice
.devSpec
= devSpec
;
131 ret
= CallCI(&ciArgs
);
132 if (ret
!= 0) return kCIError
;
134 phandle
= ciArgs
.args
.finddevice
.phandle
;
139 // InstanceToPath take an ihandle, buf and buflen. Set the device path
140 // to the package in buf upto buflen characters and returns the length
141 // Length will be -1 if the ihandle is invalid.
142 CICell
InstanceToPath(CICell ihandle
, char *buf
, long buflen
)
148 ciArgs
.service
= "instance-to-path";
151 ciArgs
.args
.instanceToPath
.ihandle
= ihandle
;
152 ciArgs
.args
.instanceToPath
.buf
= buf
;
153 ciArgs
.args
.instanceToPath
.buflen
= buflen
;
155 ret
= CallCI(&ciArgs
);
156 if (ret
!= 0) return kCIError
;
158 length
= ciArgs
.args
.instanceToPath
.length
;
163 // InstanceToPackage take an ihandle and returns the phandle for it.
164 // returns -1 if the phandle can't be found.
165 CICell
InstanceToPackage(CICell ihandle
)
171 ciArgs
.service
= "instance-to-package";
174 ciArgs
.args
.instanceToPackage
.ihandle
= ihandle
;
176 ret
= CallCI(&ciArgs
);
177 if (ret
!= 0) return kCIError
;
179 phandle
= ciArgs
.args
.instanceToPackage
.phandle
;
184 // InstanceToPackages
186 // PackageToPath take a phandle, buf and buflen. Set the device path
187 // to the package in buf upto buflen characters and returns the length
188 // Length will be -1 if the phandle is invalid.
189 CICell
PackageToPath(CICell phandle
, char *buf
, long buflen
)
195 if (gOFVersion
>= kOFVersion2x
) {
196 ciArgs
.service
= "package-to-path";
199 ciArgs
.args
.packageToPath
.phandle
= phandle
;
200 ciArgs
.args
.packageToPath
.buf
= buf
;
201 ciArgs
.args
.packageToPath
.buflen
= buflen
;
203 ret
= CallCI(&ciArgs
);
204 if (ret
!= 0) return kCIError
;
206 length
= ciArgs
.args
.packageToPath
.length
;
208 ret
= CallMethod(3, 1, SLWordsIH
, "slw_pwd", phandle
,
209 (CICell
)buf
, buflen
, &length
);
210 if (ret
!= 0) return kCIError
;
220 // GetPropLen takes a phandle and prop name
221 // and returns the size of the property
222 // or -1 if the property is not valid.
223 CICell
GetPropLen(CICell phandle
, char *name
)
229 ciArgs
.service
= "getproplen";
232 ciArgs
.args
.getproplen
.phandle
= phandle
;
233 ciArgs
.args
.getproplen
.name
= name
;
235 ret
= CallCI(&ciArgs
);
236 if (ret
!= 0) return kCIError
;
238 size
= ciArgs
.args
.getproplen
.size
;
243 // GetProp takes a phandle, prop name, buffer and length
244 // and copied the property value in to the buffer.
245 // returns -1 if the property is not valid.
246 CICell
GetProp(CICell phandle
, char *name
, char *buf
, long buflen
)
252 ciArgs
.service
= "getprop";
255 ciArgs
.args
.getprop
.phandle
= phandle
;
256 ciArgs
.args
.getprop
.name
= name
;
257 ciArgs
.args
.getprop
.buf
= buf
;
258 ciArgs
.args
.getprop
.buflen
= buflen
;
260 ret
= CallCI(&ciArgs
);
261 if (ret
!= 0) return kCIError
;
263 size
= ciArgs
.args
.getprop
.size
;
268 // NextProp takes a phandle, prev name, and a buffer
269 // and copied the next property name in to the buffer.
270 // returns -1 if the property is not valid.
271 // returns 0 if the prev was the last property.
272 // returns 1 otherwise.
273 CICell
NextProp(CICell phandle
, char *previous
, char *buf
)
279 ciArgs
.service
= "nextprop";
282 ciArgs
.args
.nextprop
.phandle
= phandle
;
283 ciArgs
.args
.nextprop
.previous
= previous
;
284 ciArgs
.args
.nextprop
.buf
= buf
;
286 ret
= CallCI(&ciArgs
);
287 if (ret
!= 0) return kCIError
;
289 flag
= ciArgs
.args
.nextprop
.flag
;
294 // SetProp takes a phandle, prop name, buffer and length
295 // and copied the buffer in to the property value.
296 // returns -1 if the property could not be set or created.
297 CICell
SetProp(CICell phandle
, char *name
, char *buf
, long buflen
)
303 ciArgs
.service
= "setprop";
306 ciArgs
.args
.setprop
.phandle
= phandle
;
307 ciArgs
.args
.setprop
.name
= name
;
308 ciArgs
.args
.setprop
.buf
= buf
;
309 ciArgs
.args
.setprop
.buflen
= buflen
;
311 ret
= CallCI(&ciArgs
);
312 if (ret
!= 0) return kCIError
;
314 size
= ciArgs
.args
.setprop
.size
;
322 // Open takes a device specifier and returns an iHandle
323 // It returns zero if the device can not be found or opened.
324 CICell
Open(char *devSpec
)
330 ciArgs
.service
= "open";
333 ciArgs
.args
.open
.devSpec
= devSpec
;
335 ret
= CallCI(&ciArgs
);
336 if (ret
!= 0) return 0;
338 ihandle
= ciArgs
.args
.open
.ihandle
;
343 // Close takes an iHandle and closes the device.
344 void Close(CICell ihandle
)
348 ciArgs
.service
= "close";
351 ciArgs
.args
.close
.ihandle
= ihandle
;
356 // Read takes an iHandle, an address and a length and return the actual
357 // Length read. Returns -1 if the operaction failed.
358 CICell
Read(CICell ihandle
, long addr
, long length
)
364 ciArgs
.service
= "read";
367 ciArgs
.args
.read
.ihandle
= ihandle
;
368 ciArgs
.args
.read
.addr
= addr
;
369 ciArgs
.args
.read
.length
= length
;
371 ret
= CallCI(&ciArgs
);
372 if (ret
!= 0) return kCIError
;
374 actual
= ciArgs
.args
.read
.actual
;
376 // Spin the wait cursor.
382 // Write takes an iHandle, an address and a length and return the actual
383 // Length written. Returns -1 if the operaction failed.
384 CICell
Write(CICell ihandle
, long addr
, long length
)
390 ciArgs
.service
= "write";
393 ciArgs
.args
.write
.ihandle
= ihandle
;
394 ciArgs
.args
.write
.addr
= addr
;
395 ciArgs
.args
.write
.length
= length
;
397 ret
= CallCI(&ciArgs
);
398 if (ret
!= 0) return kCIError
;
400 actual
= ciArgs
.args
.write
.actual
;
405 // Seek takes an iHandle, and a 64 bit position
406 // and moves to that address in file.
407 // returns seeks result, or -1 if seek is not supported.
408 CICell
Seek(CICell ihandle
, long long position
)
413 ciArgs
.service
= "seek";
416 ciArgs
.args
.seek
.ihandle
= ihandle
;
417 ciArgs
.args
.seek
.pos_high
= position
>> 32;
418 ciArgs
.args
.seek
.pos_low
= position
& 0x00000000FFFFFFFFULL
;
420 ret
= CallCI(&ciArgs
);
421 if (ret
!= 0) return kCIError
;
423 ret
= ciArgs
.args
.seek
.result
;
429 // Other Device Method Invocation
431 // Call the specified method on the given iHandle with the listed arguments.
432 long CallMethod(long args
, long rets
, CICell iHandle
, const char *method
, ...)
436 long ret
, cnt
, error
= kCINoError
;
438 va_start(argList
, method
);
440 ciArgs
.service
= "call-method";
441 ciArgs
.nArgs
= args
+ 2;
442 ciArgs
.nReturns
= rets
+ 1;
443 ciArgs
.args
.callMethod
.iHandle
= iHandle
;
444 ciArgs
.args
.callMethod
.method
= method
;
446 for (cnt
= 0; cnt
< args
; cnt
++) {
447 ciArgs
.args
.callMethod
.cells
[args
- cnt
- 1] = va_arg(argList
, CICell
);
450 ret
= CallCI(&ciArgs
);
451 if (ret
!= 0) error
= kCIError
;
452 else if (ciArgs
.args
.callMethod
.cells
[args
] != 0) error
= kCICatch
;
454 if (error
== kCINoError
) {
455 for (cnt
= 0; cnt
< rets
; cnt
++) {
456 *(va_arg(argList
, CICell
*)) =
457 ciArgs
.args
.callMethod
.cells
[args
+ rets
- cnt
];
469 // Claim takes a virt address, a size, and an alignment.
470 // It return baseaddr or -1 for claim failed.
471 CICell
Claim(CICell virt
, CICell size
, CICell align
)
477 if (gOFVersion
>= kOFVersion2x
) {
478 // Claim actually works, so use it.
479 ciArgs
.service
= "claim";
482 ciArgs
.args
.claim
.virt
= virt
;
483 ciArgs
.args
.claim
.size
= size
;
484 ciArgs
.args
.claim
.align
= align
;
486 ret
= CallCI(&ciArgs
);
487 if (ret
!= 0) return kCIError
;
489 baseaddr
= ciArgs
.args
.claim
.baseaddr
;
491 // Claim does not work. Do it by hand.
492 if ((gMMUIH
== 0) || (gMMUIH
== 0)) return kCIError
;
494 // Get the physical memory
495 ret
= CallMethod(3, 1, gMemoryIH
, "claim", virt
, size
, 0, &baseaddr
);
496 if ((ret
!= kCINoError
) || (virt
!= baseaddr
)) return kCIError
;
498 // Get the logical memory
499 ret
= CallMethod(3, 1, gMMUIH
, "claim", virt
, size
, 0, &baseaddr
);
500 if ((ret
!= kCINoError
) || (virt
!= baseaddr
)) return kCIError
;
502 // Map them together.
503 ret
= CallMethod(4, 0, gMMUIH
, "map", virt
, virt
, size
, 0);
504 if (ret
!= kCINoError
) return kCIError
;
510 // Release takes a virt address, a size
511 void Release(CICell virt
, CICell size
)
515 ciArgs
.service
= "release";
518 ciArgs
.args
.claim
.virt
= virt
;
519 ciArgs
.args
.claim
.size
= size
;
527 // Boot trys to boot the bootspec
528 void Boot(char *bootspec
)
532 ciArgs
.service
= "boot";
535 ciArgs
.args
.boot
.bootspec
= bootspec
;
540 // Enter the user interface.
541 // Executing the 'go' command returns to the client.
546 ciArgs
.service
= "enter";
553 // Exit the client program.
558 ciArgs
.service
= "exit";
567 // Quiesce stops any async tasks in Open Firmware.
572 ciArgs
.service
= "quiesce";
582 // Interpret the given forth string with the listed arguments.
583 long Interpret(long args
, long rets
, const char *forthString
, ...)
587 long ret
, cnt
, error
= kCINoError
;
589 va_start(argList
, forthString
);
591 ciArgs
.service
= "interpret";
592 ciArgs
.nArgs
= args
+ 1;
593 ciArgs
.nReturns
= rets
+ 1;
594 ciArgs
.args
.interpret
.forth
= forthString
;
596 for (cnt
= 0; cnt
< args
; cnt
++) {
597 ciArgs
.args
.interpret
.cells
[args
- cnt
- 1] = va_arg(argList
, CICell
);
600 ret
= CallCI(&ciArgs
);
601 if (ret
!= 0) error
= kCIError
;
602 else if (ciArgs
.args
.interpret
.cells
[args
] != 0) error
= kCICatch
;
604 if (error
== kCINoError
) {
605 for (cnt
= 0; cnt
< rets
; cnt
++) {
606 *(va_arg(argList
, CICell
*)) =
607 ciArgs
.args
.interpret
.cells
[args
+ rets
- cnt
];