fdcd93629a378f1669ee07a0dde2625bec0e80d4
[openwrt.git] / target / linux / olpc / files-2.6.23 / arch / i386 / kernel / ofw.c
1 /*
2  * ofw.c - Open Firmware client interface for 32-bit systems.
3  * This code is intended to be portable to any 32-bit Open Firmware
4  * implementation with a standard client interface that can be
5  * called when Linux is running.
6  *
7  * Copyright (C) 2007  Mitch Bradley <wmb@firmworks.com>
8  * Copyright (C) 2007  Andres Salomon <dilinger@debian.org>
9  */
10
11 #include <stdarg.h>
12 #include <linux/spinlock.h>
13 #include <linux/module.h>
14 #include <asm/ofw.h>
15
16
17 int (*call_firmware)(int *);
18
19 static DEFINE_SPINLOCK(prom_lock);
20
21 #define MAXARGS 20
22
23 /*
24  * The return value from ofw() in all cases is 0 if the attempt to call the
25  * function succeeded, <0 otherwise.  That return value is from the
26  * gateway function only.  Any results from the called function are returned
27  * via output argument pointers. 
28  *
29  * Here are call templates for all the standard OFW client services:
30  *
31  * ofw("test", 1, 1, namestr, &missing);
32  * ofw("peer", 1, 1, phandle, &sibling_phandle);
33  * ofw("child", 1, 1, phandle, &child_phandle);
34  * ofw("parent", 1, 1, phandle, &parent_phandle);
35  * ofw("instance_to_package", 1, 1, ihandle, &phandle);
36  * ofw("getproplen", 2, 1, phandle, namestr, &proplen);
37  * ofw("getprop", 4, 1, phandle, namestr, bufaddr, buflen, &size);
38  * ofw("nextprop", 3, 1, phandle, previousstr, bufaddr, &flag);
39  * ofw("setprop", 4, 1, phandle, namestr, bufaddr, len, &size);
40  * ofw("canon", 3, 1, devspecstr, bufaddr, buflen, &length);
41  * ofw("finddevice", 1, 1, devspecstr, &phandle);
42  * ofw("instance-to-path", 3, 1, ihandle, bufaddr, buflen, &length);
43  * ofw("package-to-path", 3, 1, phandle, bufaddr, buflen, &length);
44  * ofw("call_method", numin, numout, in0, in1, ..., &out0, &out1, ...);
45  * ofw("open", 1, 1, devspecstr, &ihandle);
46  * ofw("close", 1, 0, ihandle);
47  * ofw("read", 3, 1, ihandle, addr, len, &actual);
48  * ofw("write", 3, 1, ihandle, addr, len, &actual);
49  * ofw("seek", 3, 1, ihandle, pos_hi, pos_lo, &status);
50  * ofw("claim", 3, 1, virtaddr, size, align, &baseaddr);
51  * ofw("release", 2, 0, virtaddr, size);
52  * ofw("boot", 1, 0, bootspecstr);
53  * ofw("enter", 0, 0);
54  * ofw("exit", 0, 0);
55  * ofw("chain", 5, 0, virtaddr, size, entryaddr, argsaddr, len);
56  * ofw("interpret", numin+1, numout+1, cmdstr, in0, ..., &catchres, &out0, ...);
57  * ofw("set-callback", 1, 1, newfuncaddr, &oldfuncaddr);
58  * ofw("set-symbol-lookup", 2, 0, symtovaladdr, valtosymaddr);
59  * ofw("milliseconds", 0, 1, &ms);
60  */
61
62 int ofw(char *name, int numargs, int numres, ...)
63 {
64         va_list ap;
65         int argarray[MAXARGS+3];
66         int argnum = 3;
67         int retval;
68         int *intp;
69         unsigned long flags;
70
71         if (!call_firmware)
72                 return -1;
73         if ((numargs + numres) > MAXARGS)
74                 return -1;      /* spit out an error? */
75
76         argarray[0] = (int) name;
77         argarray[1] = numargs;
78         argarray[2] = numres;
79
80         va_start(ap, numres);
81         while (numargs) {
82                 argarray[argnum++] = va_arg(ap, int);
83                 numargs--;
84         }
85
86         spin_lock_irqsave(&prom_lock, flags);
87         retval = call_firmware(argarray);
88         spin_unlock_irqrestore(&prom_lock, flags);
89
90         if (retval == 0) {
91                 while (numres) {
92                         intp = va_arg(ap, int *);
93                         *intp = argarray[argnum++];
94                         numres--;
95                 }
96         }
97         va_end(ap);
98         return retval;
99 }
100 EXPORT_SYMBOL(ofw);