2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * ci.c - Functions for accessing Open Firmware's Client Interface
25 * Copyright (c) 1998-2002 Apple Computer, Inc.
32 static ClientInterfacePtr gCIPtr
;
34 long InitCI(ClientInterfacePtr ciPtr
)
41 long CallCI(CIArgs
*ciArgsPtr
)
45 ret
= (*gCIPtr
)(ciArgsPtr
);
52 // Peer take a phandle and returns the next peer.
53 // It returns zero of there are no more peers.
54 CICell
Peer(CICell phandle
)
60 ciArgs
.service
= "peer";
63 ciArgs
.args
.peer
.phandle
= phandle
;
65 ret
= CallCI(&ciArgs
);
66 if (ret
!= 0) return kCIError
;
68 peer_ph
= ciArgs
.args
.peer
.peerPhandle
;
73 // Child take a phandle and returns the first child.
74 // It returns zero of there in no child.
75 CICell
Child(CICell phandle
)
81 ciArgs
.service
= "child";
84 ciArgs
.args
.child
.phandle
= phandle
;
86 ret
= CallCI(&ciArgs
);
87 if (ret
!= 0) return kCIError
;
89 child_ph
= ciArgs
.args
.child
.childPhandle
;
94 // Parent take a phandle and returns the parent node.
95 // It returns zero of if the phandle is the root node.
96 CICell
Parent(CICell phandle
)
102 ciArgs
.service
= "parent";
105 ciArgs
.args
.parent
.childPhandle
= phandle
;
107 ret
= CallCI(&ciArgs
);
108 if (ret
!= 0) return kCIError
;
110 parent_ph
= ciArgs
.args
.parent
.parentPhandle
;
115 // FindDevice take a device spec and returns the phandle.
116 // It returns zero of if the device was not found.
117 CICell
FindDevice(char *devSpec
)
123 ciArgs
.service
= "finddevice";
126 ciArgs
.args
.finddevice
.devSpec
= devSpec
;
128 ret
= CallCI(&ciArgs
);
129 if (ret
!= 0) return kCIError
;
131 phandle
= ciArgs
.args
.finddevice
.phandle
;
136 // InstanceToPath take an ihandle, buf and buflen. Set the device path
137 // to the package in buf upto buflen characters and returns the length
138 // Length will be -1 if the ihandle is invalid.
139 CICell
InstanceToPath(CICell ihandle
, char *buf
, long buflen
)
145 ciArgs
.service
= "instance-to-path";
148 ciArgs
.args
.instanceToPath
.ihandle
= ihandle
;
149 ciArgs
.args
.instanceToPath
.buf
= buf
;
150 ciArgs
.args
.instanceToPath
.buflen
= buflen
;
152 ret
= CallCI(&ciArgs
);
153 if (ret
!= 0) return kCIError
;
155 length
= ciArgs
.args
.instanceToPath
.length
;
160 // InstanceToPackage take an ihandle and returns the phandle for it.
161 // returns -1 if the phandle can't be found.
162 CICell
InstanceToPackage(CICell ihandle
)
168 ciArgs
.service
= "instance-to-package";
171 ciArgs
.args
.instanceToPackage
.ihandle
= ihandle
;
173 ret
= CallCI(&ciArgs
);
174 if (ret
!= 0) return kCIError
;
176 phandle
= ciArgs
.args
.instanceToPackage
.phandle
;
181 // InstanceToPackages
183 // PackageToPath take a phandle, buf and buflen. Set the device path
184 // to the package in buf upto buflen characters and returns the length
185 // Length will be -1 if the phandle is invalid.
186 CICell
PackageToPath(CICell phandle
, char *buf
, long buflen
)
192 if (gOFVersion
>= kOFVersion2x
) {
193 ciArgs
.service
= "package-to-path";
196 ciArgs
.args
.packageToPath
.phandle
= phandle
;
197 ciArgs
.args
.packageToPath
.buf
= buf
;
198 ciArgs
.args
.packageToPath
.buflen
= buflen
;
200 ret
= CallCI(&ciArgs
);
201 if (ret
!= 0) return kCIError
;
203 length
= ciArgs
.args
.packageToPath
.length
;
205 ret
= CallMethod(3, 1, SLWordsIH
, "slw_pwd", phandle
,
206 (CICell
)buf
, buflen
, &length
);
207 if (ret
!= 0) return kCIError
;
217 // GetPropLen takes a phandle and prop name
218 // and returns the size of the property
219 // or -1 if the property is not valid.
220 CICell
GetPropLen(CICell phandle
, char *name
)
226 ciArgs
.service
= "getproplen";
229 ciArgs
.args
.getproplen
.phandle
= phandle
;
230 ciArgs
.args
.getproplen
.name
= name
;
232 ret
= CallCI(&ciArgs
);
233 if (ret
!= 0) return kCIError
;
235 size
= ciArgs
.args
.getproplen
.size
;
240 // GetProp takes a phandle, prop name, buffer and length
241 // and copied the property value in to the buffer.
242 // returns -1 if the property is not valid.
243 CICell
GetProp(CICell phandle
, char *name
, char *buf
, long buflen
)
249 ciArgs
.service
= "getprop";
252 ciArgs
.args
.getprop
.phandle
= phandle
;
253 ciArgs
.args
.getprop
.name
= name
;
254 ciArgs
.args
.getprop
.buf
= buf
;
255 ciArgs
.args
.getprop
.buflen
= buflen
;
257 ret
= CallCI(&ciArgs
);
258 if (ret
!= 0) return kCIError
;
260 size
= ciArgs
.args
.getprop
.size
;
265 // NextProp takes a phandle, prev name, and a buffer
266 // and copied the next property name in to the buffer.
267 // returns -1 if the property is not valid.
268 // returns 0 if the prev was the last property.
269 // returns 1 otherwise.
270 CICell
NextProp(CICell phandle
, char *previous
, char *buf
)
276 ciArgs
.service
= "nextprop";
279 ciArgs
.args
.nextprop
.phandle
= phandle
;
280 ciArgs
.args
.nextprop
.previous
= previous
;
281 ciArgs
.args
.nextprop
.buf
= buf
;
283 ret
= CallCI(&ciArgs
);
284 if (ret
!= 0) return kCIError
;
286 flag
= ciArgs
.args
.nextprop
.flag
;
291 // SetProp takes a phandle, prop name, buffer and length
292 // and copied the buffer in to the property value.
293 // returns -1 if the property could not be set or created.
294 CICell
SetProp(CICell phandle
, char *name
, char *buf
, long buflen
)
300 ciArgs
.service
= "setprop";
303 ciArgs
.args
.setprop
.phandle
= phandle
;
304 ciArgs
.args
.setprop
.name
= name
;
305 ciArgs
.args
.setprop
.buf
= buf
;
306 ciArgs
.args
.setprop
.buflen
= buflen
;
308 ret
= CallCI(&ciArgs
);
309 if (ret
!= 0) return kCIError
;
311 size
= ciArgs
.args
.setprop
.size
;
319 // Open takes a device specifier and returns an iHandle
320 // It returns zero if the device can not be found or opened.
321 CICell
Open(char *devSpec
)
327 // intercept software RAID's virtual devices
328 if(isRAIDPath(devSpec
))
329 return (CICell
)RAIDOpen(devSpec
);
331 ciArgs
.service
= "open";
334 ciArgs
.args
.open
.devSpec
= devSpec
;
336 ret
= CallCI(&ciArgs
);
337 if (ret
!= 0) return 0;
339 ihandle
= ciArgs
.args
.open
.ihandle
;
344 // Close takes an iHandle and closes the device.
345 void Close(CICell ihandle
)
349 if(isRAIDDevice((void*)ihandle
)) {
350 RAIDClose((RAIDDevicePtr
)ihandle
);
354 ciArgs
.service
= "close";
357 ciArgs
.args
.close
.ihandle
= ihandle
;
362 // Read takes an iHandle, an address and a length and return the actual
363 // Length read. Returns -1 if the operaction failed.
364 CICell
Read(CICell ihandle
, long addr
, long length
)
370 if(isRAIDDevice((void*)ihandle
))
371 return RAIDRead((RAIDDevicePtr
)ihandle
, addr
, length
, -1);
373 ciArgs
.service
= "read";
376 ciArgs
.args
.read
.ihandle
= ihandle
;
377 ciArgs
.args
.read
.addr
= addr
;
378 ciArgs
.args
.read
.length
= length
;
380 ret
= CallCI(&ciArgs
);
381 if (ret
!= 0) return kCIError
;
383 actual
= ciArgs
.args
.read
.actual
;
385 // Spin the wait cursor.
391 // Write takes an iHandle, an address and a length and return the actual
392 // Length written. Returns -1 if the operaction failed.
393 CICell
Write(CICell ihandle
, long addr
, long length
)
399 if(isRAIDDevice((void*)ihandle
)) {
400 printf("who's trying to write to RAID?!\n");
404 ciArgs
.service
= "write";
407 ciArgs
.args
.write
.ihandle
= ihandle
;
408 ciArgs
.args
.write
.addr
= addr
;
409 ciArgs
.args
.write
.length
= length
;
411 ret
= CallCI(&ciArgs
);
412 if (ret
!= 0) return kCIError
;
414 actual
= ciArgs
.args
.write
.actual
;
419 // Seek takes an iHandle, and a 64 bit position
420 // and moves to that address in file.
421 // returns seeks result, or -1 if seek is not supported.
422 CICell
Seek(CICell ihandle
, long long position
)
427 if(isRAIDDevice((void*)ihandle
))
428 return RAIDSeek((RAIDDevicePtr
)ihandle
, position
);
430 ciArgs
.service
= "seek";
433 ciArgs
.args
.seek
.ihandle
= ihandle
;
434 ciArgs
.args
.seek
.pos_high
= position
>> 32;
435 ciArgs
.args
.seek
.pos_low
= position
& 0x00000000FFFFFFFFULL
;
437 ret
= CallCI(&ciArgs
);
438 if (ret
!= 0) return kCIError
;
440 ret
= ciArgs
.args
.seek
.result
;
446 // Other Device Method Invocation
448 // Call the specified method on the given iHandle with the listed arguments.
449 long CallMethod(long args
, long rets
, CICell iHandle
, const char *method
, ...)
453 long ret
, cnt
, error
= kCINoError
;
455 va_start(argList
, method
);
457 ciArgs
.service
= "call-method";
458 ciArgs
.nArgs
= args
+ 2;
459 ciArgs
.nReturns
= rets
+ 1;
460 ciArgs
.args
.callMethod
.iHandle
= iHandle
;
461 ciArgs
.args
.callMethod
.method
= method
;
463 for (cnt
= 0; cnt
< args
; cnt
++) {
464 ciArgs
.args
.callMethod
.cells
[args
- cnt
- 1] = va_arg(argList
, CICell
);
467 ret
= CallCI(&ciArgs
);
468 if (ret
!= 0) error
= kCIError
;
469 else if (ciArgs
.args
.callMethod
.cells
[args
] != 0) error
= kCICatch
;
471 if (error
== kCINoError
) {
472 for (cnt
= 0; cnt
< rets
; cnt
++) {
473 *(va_arg(argList
, CICell
*)) =
474 ciArgs
.args
.callMethod
.cells
[args
+ rets
- cnt
];
486 // Claim takes a virt address, a size, and an alignment.
487 // It return baseaddr or -1 for claim failed.
488 CICell
Claim(CICell virt
, CICell size
, CICell align
)
494 if (gOFVersion
>= kOFVersion2x
) {
495 // Claim actually works, so use it.
496 ciArgs
.service
= "claim";
499 ciArgs
.args
.claim
.virt
= virt
;
500 ciArgs
.args
.claim
.size
= size
;
501 ciArgs
.args
.claim
.align
= align
;
503 ret
= CallCI(&ciArgs
);
504 if (ret
!= 0) return kCIError
;
506 baseaddr
= ciArgs
.args
.claim
.baseaddr
;
508 // Claim does not work. Do it by hand.
509 if ((gMMUIH
== 0) || (gMMUIH
== 0)) return kCIError
;
511 // Get the physical memory
512 ret
= CallMethod(3, 1, gMemoryIH
, "claim", virt
, size
, 0, &baseaddr
);
513 if ((ret
!= kCINoError
) || (virt
!= baseaddr
)) return kCIError
;
515 // Get the logical memory
516 ret
= CallMethod(3, 1, gMMUIH
, "claim", virt
, size
, 0, &baseaddr
);
517 if ((ret
!= kCINoError
) || (virt
!= baseaddr
)) return kCIError
;
519 // Map them together.
520 ret
= CallMethod(4, 0, gMMUIH
, "map", virt
, virt
, size
, 0);
521 if (ret
!= kCINoError
) return kCIError
;
527 // Release takes a virt address, a size
528 void Release(CICell virt
, CICell size
)
532 ciArgs
.service
= "release";
535 ciArgs
.args
.claim
.virt
= virt
;
536 ciArgs
.args
.claim
.size
= size
;
544 // Boot trys to boot the bootspec
545 void Boot(char *bootspec
)
549 ciArgs
.service
= "boot";
552 ciArgs
.args
.boot
.bootspec
= bootspec
;
557 // Enter the user interface.
558 // Executing the 'go' command returns to the client.
563 ciArgs
.service
= "enter";
570 // Exit the client program.
575 ciArgs
.service
= "exit";
584 // Quiesce stops any async tasks in Open Firmware.
589 ciArgs
.service
= "quiesce";
599 // Interpret the given forth string with the listed arguments.
600 long Interpret(long args
, long rets
, const char *forthString
, ...)
604 long ret
, cnt
, error
= kCINoError
;
606 va_start(argList
, forthString
);
608 ciArgs
.service
= "interpret";
609 ciArgs
.nArgs
= args
+ 1;
610 ciArgs
.nReturns
= rets
+ 1;
611 ciArgs
.args
.interpret
.forth
= forthString
;
613 for (cnt
= 0; cnt
< args
; cnt
++) {
614 ciArgs
.args
.interpret
.cells
[args
- cnt
- 1] = va_arg(argList
, CICell
);
617 ret
= CallCI(&ciArgs
);
618 if (ret
!= 0) error
= kCIError
;
619 else if (ciArgs
.args
.interpret
.cells
[args
] != 0) error
= kCICatch
;
621 if (error
== kCINoError
) {
622 for (cnt
= 0; cnt
< rets
; cnt
++) {
623 *(va_arg(argList
, CICell
*)) =
624 ciArgs
.args
.interpret
.cells
[args
+ rets
- cnt
];