aml_device.bend
bend-osdev-acpi@0.1.2.0 · 177 lines · 0 definitions
1# bend-osdev-acpi, aml_device.bend: the device objects OSPM reads most
2# (ACPI 6.5, chapter 6, Device Configuration): _HID (6.1.5) and its EISA ID
3# form (EISAID, chapter 19), _STA (6.3.7), _CRS (6.2.2, resource templates:
4# aml_resource.bend) and _PRT (6.2.13, PCI interrupt routing), and the
5# devices of a namespace.
6import Base
7import bend-osdev-word64@0.1.1.1/word64.bend as W
8import bend-osdev-bytes@0.1.1.1/bytes.bend as B
9import bend-osdev-acpi@0.1.2.0/error.bend as E
10import bend-osdev-acpi@0.1.2.0/aml_value.bend as V
11import bend-osdev-acpi@0.1.2.0/aml_ns.bend as S
12import bend-osdev-acpi@0.1.2.0/aml_host.bend as Hs
13import bend-osdev-acpi@0.1.2.0/aml_interp.bend as I
14import bend-osdev-acpi@0.1.2.0/aml.bend as A
15import bend-osdev-acpi@0.1.2.0/aml_resource.bend as R
16
17# EISA IDs: a DWord holding three letters of five bits and four hex digits,
18# most significant byte first in memory ("PNP0A03" is 0x030AD041)
19
20def dv.hex.pick(lt: Bool, +d: U32) -> U32:
21 match lt:
22 case True{}:
23 U32.add(48, d)
24 case False{}:
25 U32.add(55, d)
26
27def dv.hex(+d: U32) -> U32:
28 dv.hex.pick(U32.is_lt(d, 10), d)
29
30def AmlEisaId.text(+v: U32) -> String:
31 +id = U32.or(U32.or(U32.shln(U32.and(v, 255), 24n), U32.shln(U32.and(U32.shrn(v, 8n), 255), 16n)), U32.or(U32.shln(U32.and(U32.shrn(v, 16n), 255), 8n), U32.and(U32.shrn(v, 24n), 255)))
32 B.to_string([U32.add(64, U32.and(U32.shrn(id, 26n), 31)), U32.add(64, U32.and(U32.shrn(id, 21n), 31)), U32.add(64, U32.and(U32.shrn(id, 16n), 31)), dv.hex(U32.and(U32.shrn(id, 12n), 15)), dv.hex(U32.and(U32.shrn(id, 8n), 15)), dv.hex(U32.and(U32.shrn(id, 4n), 15)), dv.hex(U32.and(id, 15))])
33
34# The objects of a device
35
36def dv.get.pick(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, has: Bool, +s: A.AmlSystem<H>, +p: String, +n: Nat) -> Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>:
37 match has:
38 case True{}:
39 Some{A.AmlOutcome.result(H, A.Aml.eval(~H, ~io, s, p, Nil{}, n))}
40 case False{}:
41 None{}
42
43# an object of a device evaluated (a method run with no arguments), in at
44# most n steps; None if the device has no such object
45def AmlDevice.get(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, +s: A.AmlSystem<H>, +dev: String, +seg: String, +n: Nat) -> Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>:
46 +p = S.AmlPath.child(dev, seg)
47 dv.get.pick(~H, ~io, S.AmlNs.has(A.AmlSystem.ns(H, s), p), s, p, n)
48
49def dv.sta(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Result<&2, &2, E.AcpiError, W.W64>:
50 match m:
51 case None{}:
52 Done{W.W64.from_u32(15)}
53 case Some{Fail{e}}:
54 Fail{e}
55 case Some{Done{v}}:
56 V.AmlValue.to_int(True{}, v)
57
58# _STA: bit 0 present, 1 enabled, 2 shown in the UI, 3 functioning,
59# 4 battery present; a device without _STA is 0x0F (6.3.7)
60def AmlDevice.status(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, +s: A.AmlSystem<H>, +dev: String, +n: Nat) -> Result<&2, &2, E.AcpiError, W.W64>:
61 dv.sta(AmlDevice.get(~H, ~io, s, dev, "_STA", n))
62
63def dv.id(v: V.AmlValue) -> Result<&2, &2, E.AcpiError, String>:
64 match v:
65 case V.AmlInt{x}:
66 Done{AmlEisaId.text(W.W64.lo(x))}
67 case V.AmlStr{t}:
68 Done{B.Octets.to_string(t)}
69 case _:
70 Fail{E.AcpiAmlBadType{"_HID is not an integer or a string"}}
71
72def dv.hid(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Maybe<&2, Result<&2, &2, E.AcpiError, String>>:
73 match m:
74 case None{}:
75 None{}
76 case Some{Fail{e}}:
77 Some{Fail{e}}
78 case Some{Done{v}}:
79 Some{dv.id(v)}
80
81# _HID as text: an EISA ID ("PNP0A03") or the string itself ("ACPI0003")
82def AmlDevice.hid(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, +s: A.AmlSystem<H>, +dev: String, +n: Nat) -> Maybe<&2, Result<&2, &2, E.AcpiError, String>>:
83 dv.hid(AmlDevice.get(~H, ~io, s, dev, "_HID", n))
84
85def dv.crs(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Result<&2, &2, E.AcpiError, List<&2, R.AmlResource>>:
86 match m:
87 case None{}:
88 Done{Nil{}}
89 case Some{Fail{e}}:
90 Fail{e}
91 case Some{Done{V.AmlBuf{b}}}:
92 R.AmlResource.parse(b)
93 case Some{Done{v}}:
94 Fail{E.AcpiAmlBadType{"_CRS is not a buffer"}}
95
96# _CRS: the resources the device uses (none if it has no _CRS)
97def AmlDevice.crs(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, +s: A.AmlSystem<H>, +dev: String, +n: Nat) -> Result<&2, &2, E.AcpiError, List<&2, R.AmlResource>>:
98 dv.crs(AmlDevice.get(~H, ~io, s, dev, "_CRS", n))
99
100# _PRT entries (6.2.13): the device's address (high word: device, low word:
101# 0xFFFF for any function), the PCI pin (0 INTA to 3 INTD), and the source:
102# the path of a link device and its index, or an empty path and the global
103# system interrupt in index
104type AmlPrtEntry is Data:
105 AmlPrtEntry{address: W.W64, pin: U32, source: String, index: U32}
106
107def dv.prt.src(v: V.AmlValue) -> String:
108 match v:
109 case V.AmlRef{V.AmlLName{p}}:
110 p
111 case V.AmlStr{t}:
112 B.Octets.to_string(t)
113 case _:
114 ""
115
116def dv.prt.one(v: V.AmlValue) -> Result<&2, &2, E.AcpiError, AmlPrtEntry>:
117 match v:
118 case V.AmlPkg{[V.AmlInt{a}, V.AmlInt{p}, src, V.AmlInt{i}]}:
119 Done{AmlPrtEntry{a, W.W64.lo(p), dv.prt.src(src), W.W64.lo(i)}}
120 case _:
121 Fail{E.AcpiAmlBadType{"a _PRT entry is not a package of four"}}
122
123def dv.prt.cons(r: Result<&2, &2, E.AcpiError, AmlPrtEntry>, rs: Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>:
124 match r rs:
125 case Done{e} Done{es}:
126 Done{Con{e, es}}
127 case Fail{e} _:
128 Fail{e}
129 case Done{e} Fail{x}:
130 Fail{x}
131
132def dv.prt.all(xs: List<&2, V.AmlValue>) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>:
133 match xs:
134 case Nil{}:
135 Done{Nil{}}
136 case Con{x, t}:
137 dv.prt.cons(dv.prt.one(x), dv.prt.all(t))
138
139def dv.prt(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>:
140 match m:
141 case None{}:
142 Done{Nil{}}
143 case Some{Fail{e}}:
144 Fail{e}
145 case Some{Done{V.AmlPkg{xs}}}:
146 dv.prt.all(xs)
147 case Some{Done{v}}:
148 Fail{E.AcpiAmlBadType{"_PRT is not a package"}}
149
150# _PRT of a PCI bridge (none if it has no _PRT)
151def AmlDevice.prt(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, +s: A.AmlSystem<H>, +dev: String, +n: Nat) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>:
152 dv.prt(AmlDevice.get(~H, ~io, s, dev, "_PRT", n))
153
154def dv.kind(o: Maybe<&2, S.AmlObject>) -> U32:
155 match o:
156 case Some{x}:
157 S.AmlObject.type(x)
158 case None{}:
159 0
160
161def dv.devs.pick(dev: Bool, p: String, rest: List<&2, String>) -> List<&2, String>:
162 match dev:
163 case True{}:
164 Con{p, rest}
165 case False{}:
166 rest
167
168def dv.devs(ps: List<&2, String>, +ns: S.AmlNs) -> List<&2, String>:
169 match ps:
170 case Nil{}:
171 Nil{}
172 case Con{+p, t}:
173 dv.devs.pick(U32.is_eq(dv.kind(S.AmlNs.get(ns, p)), 6), p, dv.devs(t, ns))
174
175# every Device (and \_SB_) of a namespace, in path order
176def AmlDevice.list(+ns: S.AmlNs) -> List<&2, String>:
177 dv.devs(S.AmlNs.paths(ns), ns)