3 \ this code implements IEEE 1275-1994 path resolution
5 \ Copyright (C) 2003 Samuel Rydh
7 \ See the file "COPYING" for further information about
8 \ the copyright and warranty status of this work.
12 0 0 create interpose-args , ,
14 : expand-alias ( alias-addr alias-len -- exp-addr exp-len expanded? )
16 " /aliases" find-dev 0= if 2drop false exit then
17 get-package-property if
21 \ drop trailing 0 from string
28 \ 4.3.1 Resolve aliases
31 \ the returned string is allocated with alloc-mem
32 : pathres-resolve-aliases ( path-addr path-len -- path-addr path-len )
34 200 here + >r \ abuse dictionary for temporary storage
36 \ If the pathname does not begin with "/", and its first node name
37 \ component is an alias, replace the alias with its expansion.
38 ascii / split-before \ (PATH_NAME, "/") -> (TAIL HEAD)
39 ascii : split-before \ (HEAD, ":") -> (ALIAS_ARGS AL_NAME)
40 expand-alias ( TAIL ALIAS_ARGS EXP_ALIAS_NAME expanded? )
42 2 pick 0<> if \ If ALIAS_ARGS is not empty
43 ascii / split-after \ (ALIAS_NAME, "/") -> (AL_TAIL AL_HEAD/)
44 2swap ( TAIL AL_HEAD/ AL_TAIL )
45 ascii : split-before \ (AL_TAIL, ":") -> (DEAD_ARGS AL_TAIL)
46 2swap 2drop ( TAIL AL_ARGS AL_HEAD ALIAS_TAIL )
47 2swap ( TAIL AL_ARGS AL_TAIL AL_HEAD )
48 r> tmpstrcat tmpstrcat >r
50 2swap 2drop \ drop ALIAS_ARGS
54 \ put thing back together again
55 r> tmpstrcat tmpstrcat drop
60 ( path-addr path-len )
67 struct ( search information )
68 2 cells field >si.path
69 2 cells field >si.arguments
70 2 cells field >si.unit_addr
71 2 cells field >si.node_name
72 2 cells field >si.free_me
73 4 cells field >si.unit_phys
74 /n field >si.unit_phys_len
75 /n field >si.save-ihandle
76 /n field >si.save-phandle
77 /n field >si.top-ihandle
78 /n field >si.top-opened \ set after successful open
79 /n field >si.child \ node to match
84 \ 4.3.6 node name match criteria
87 : match-nodename ( childname len sinfo -- match? )
89 2dup r@ >si.node_name 2@
90 ( [childname] [childname] [nodename] )
91 strcmp 0= if r> 3drop true exit then
93 \ does NODE_NAME contain a comma?
94 r@ >si.node_name 2@ ascii , strchr
95 if r> 3drop false exit then
98 ascii , left-split 2drop r@ >si.node_name 2@
100 strcmp if false else true then
105 \ 4.3.4 exact match child node
108 \ If NODE_NAME is not empty, make sure it matches the name property
109 : common-match ( sinfo -- )
111 \ a) NODE_NAME nonempty
112 r@ >si.node_name 2@ nip if
113 " name" r@ >si.child @ get-package-property if -1 throw then
114 \ name is supposed to be null-terminated
116 \ exit if NODE_NAME does not match
117 r@ match-nodename 0= if -2 throw then
122 : (exact-match) ( sinfo -- )
124 \ a) If NODE_NAME is not empty, make sure it matches the name property
127 \ b) UNIT_PHYS nonempty?
128 r@ >si.unit_phys_len @ /l* ?dup if
129 \ check if unit_phys matches
130 " reg" r@ >si.child @ get-package-property if -3 throw then
131 ( unitbytes propaddr proplen )
132 rot r@ >si.unit_phys -rot
133 ( propaddr unit_phys proplen unitbytes )
134 swap over < if -4 throw then
135 comp if -5 throw then
137 \ c) both NODE_NAME and UNIT_PHYS empty?
138 r@ >si.node_name 2@ nip 0= if -6 throw then
144 : exact-match ( sinfo -- match? )
145 ['] (exact-match) catch if drop false exit then
150 \ 4.3.5 wildcard match child node
153 : (wildcard-match) ( sinfo -- match? )
155 \ a) If NODE_NAME is not empty, make sure it matches the name property
158 \ b) Fail if "reg" property exist
159 " reg" r@ >si.child @ get-package-property 0= if -7 throw then
161 \ c) Fail if both NODE_NAME and UNIT_ADDR are both empty
162 r@ >si.unit_phys_len @
163 r@ >si.node_name 2@ nip
164 or 0= if -1 throw then
170 : wildcard-match ( sinfo -- match? )
171 ['] (wildcard-match) catch if drop false exit then
177 \ 4.3.3 match child node
180 \ used if package lacks a decode-unit method
181 : def-decode-unit ( str len -- unitaddr ... )
185 : get-decode-unit-xt ( phandle -- xt )
186 " decode-unit" rot find-method
187 0= if ['] def-decode-unit then
190 : find-child ( sinfo -- phandle )
192 \ decode unit address string
193 r@ >si.unit_addr 2@ dup if
195 active-package get-decode-unit-xt
196 depth 3 - >r execute depth r@ - r> swap
197 ( ... a_lo ... a_hi olddepth n )
199 dup r@ >si.unit_phys_len !
200 ( ... a_lo ... a_hi olddepth n )
202 begin 1- dup 0>= while
203 rot r> dup la1+ >r l!-be
210 0 r@ >si.unit_phys_len !
211 \ r@ >si.unit_phys 4 cells 0 fill
217 active-package >dn.child @
220 ( xt phandle R: sinfo )
221 r@ 2 pick execute if 2drop r> >si.child @ exit then
224 ['] exact-match = if ['] wildcard-match else 0 then
232 \ 4.3.2 Create new linked instance procedure
235 : link-one ( sinfo -- )
237 active-package create-instance
238 dup 0= if -99 throw then
240 \ change instance parent
241 r@ >si.top-ihandle @ over >in.my-parent !
242 dup r@ >si.top-ihandle !
245 \ b) set my-args field
246 r@ >si.arguments 2@ strdup my-self >in.arguments 2!
248 \ e) set my-unit field
249 r@ >si.unit_addr 2@ nip if
250 \ copy UNIT_PHYS to the my-unit field
251 r@ >si.unit_phys my-self >in.my-unit 4 cells move
253 \ set unit-addr from reg property
254 " reg" active-package get-package-property 0= if
255 \ ( ihandle prop proplen )
256 \ copy address to my-unit
257 4 cells min my-self >in.my-unit swap move
260 my-self >in.my-unit 4 cells 0 fill
264 \ top instance has not been opened (yet)
265 false r> >si.top-opened !
268 : invoke-open ( sinfo -- )
269 " open" my-self ['] $call-method
270 catch if 3drop false then
273 true swap >si.top-opened !
277 \ 4.3.7 Handle interposers procedure (supplement)
280 : handle-interposers ( sinfo -- )
286 active-package swap active-package!
288 \ clear unit address and set arguments
289 0 0 r@ >si.unit_addr 2!
290 interpose-args 2@ r@ >si.arguments 2!
292 true my-self >in.interposed !
293 interpose-args 2@ free-mem
303 \ 4.3.1 Path resolution procedure
306 \ close-dev ( ihandle -- )
318 : path-res-cleanup ( sinfo close? )
320 \ tear down all instances if close? is set
322 dup >si.top-opened @ if
323 dup >si.top-ihandle @
324 ?dup if close-dev then
326 dup >si.top-ihandle @ dup
327 ( sinfo ihandle ihandle )
328 dup if >in.my-parent @ swap then
329 ( sinfo parent ihandle )
330 ?dup if destroy-instance then
331 ?dup if close-dev then
335 \ restore active-package and my-self
336 dup >si.save-ihandle @ to my-self
337 dup >si.save-phandle @ active-package!
339 \ free any allocated memory
340 dup >si.free_me 2@ free-mem
344 : (path-resolution) ( context sinfo -- )
346 ( context pathstr pathlen )
348 \ this allocates a copy of the string
349 pathres-resolve-aliases
350 2dup r@ >si.free_me 2!
352 \ If the pathname, after possible alias expansion, begins with "/",
353 \ begin the search at the root node. Otherwise, begin at the active
356 dup if \ make sure string is not empty
358 swap char+ swap /c - \ Remove the "/" from PATH_NAME.
359 \ Set the active package to the root node.
360 device-tree @ active-package!
365 0 0 r@ >si.unit_addr 2!
366 0 0 r@ >si.arguments 2!
367 0 r@ >si.top-ihandle !
369 \ If there is no active package, exit this procedure, returning false.
371 active-package 0= if -99 throw then
373 \ Begin the creation of an instance chain.
374 \ NOTE--If, at this step, the active package is not the root node and
375 \ we are in open-dev or execute-device-method contexts, the instance
376 \ chain that results from the path resolution process may be incomplete.
379 ( virt-active-node context )
381 r@ >si.path 2@ nip \ nonzero path?
383 \ ( active-node context )
384 \ is this open-dev or execute-device-method context?
387 over active-package <> my-self >in.interposed !
389 r@ handle-interposers
393 r@ >si.path 2@ ( PATH )
395 ascii / left-split ( PATH COMPONENT )
396 ascii : left-split ( PATH ARGS NODE_ADDR )
397 ascii @ left-split ( PATH ARGS UNIT_ADDR NODE_NAME )
404 ( virt-active-node context )
406 \ 4.3.1 i) pathname has a leading %?
407 r@ >si.node_name 2@ 2dup 2dup ascii % strchr nip = if
408 1- swap 1+ swap r@ >si.node_name 2!
409 " /packages" find-dev drop active-package!
413 nip r@ find-child swap over
414 ( new-node context new-node )
417 \ (optional: open any nodes between parent and child )
422 ( virt-active-node type )
423 dup if r@ link-one then
425 dup active-package <> my-self >in.interposed !
427 r@ handle-interposers
434 : path-resolution ( context path-addr path-len -- sinfo true | false )
435 \ allocate and clear the search block
436 sinfo.size alloc-mem >r
442 \ save ihandle and phandle
443 my-self r@ >si.save-ihandle !
444 active-package r@ >si.save-phandle !
446 \ save context (if we take an exception)
449 r@ ['] (path-resolution)
451 ( context xxx xxx error )
452 r> true path-res-cleanup
454 \ rethrow everything except our "cleanup throw"
455 dup -99 <> if throw then
458 \ ( context ) throw an exception if this is find-device context
459 if false else -22 throw then
469 : open-dev ( dev-str dev-len -- ihandle | 0 )
470 1 -rot path-resolution 0= if false exit then
474 false path-res-cleanup
479 : execute-device-method
480 ( ... dev-str dev-len met-str met-len -- ... false | ?? true )
482 2 -rot path-resolution 0= if 2drop false exit then
483 ( method-str method-len sinfo )
485 my-self ['] $call-method catch
486 if 3drop false else true then
487 r> true path-res-cleanup
490 : find-device ( dev-str dev-len -- )
491 2dup " .." strcmp 0= if
493 active-package dup if >dn.parent @ then
495 dup 0= if -22 throw then
499 0 -rot path-resolution 0= if false exit then
502 true path-res-cleanup
506 \ find-device, but without side effects
507 : (find-dev) ( dev-str dev-len -- phandle true | false )
509 ['] find-device catch if 3drop false exit then
510 active-package swap active-package! true
513 \ Tuck on a node at the end of the chain being created.
514 \ This implementation follows the interpose recommended practice
517 : interpose ( arg-str arg-len phandle -- )
519 strdup interpose-args 2!
522 ['] (find-dev) to find-dev