xref: /haiku/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp (revision 106388ddbfdd00f4409c86bd3fe8d581bae532ec)
1 /*
2  * Copyright 2014, Ithamar R. Adema <ithamar@upgrade-android.com>
3  * All rights reserved. Distributed under the terms of the MIT License.
4  *
5  * Copyright 2015-2022, Haiku, Inc. All rights reserved.
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include <drivers/bus/FDT.h>
11 #include <KernelExport.h>
12 #include <util/kernel_cpp.h>
13 #include <util/Vector.h>
14 #include <device_manager.h>
15 
16 #include <AutoDeleter.h>
17 #include <AutoDeleterDrivers.h>
18 #include <HashMap.h>
19 #include <debug.h>
20 
21 extern "C" {
22 #include <libfdt_env.h>
23 #include <fdt.h>
24 #include <libfdt.h>
25 };
26 
27 
28 //#define TRACE_FDT
29 #ifdef TRACE_FDT
30 #define TRACE(x...) dprintf(x)
31 #else
32 #define TRACE(x...)
33 #endif
34 
35 
36 #define GIC_INTERRUPT_CELL_TYPE     0
37 #define GIC_INTERRUPT_CELL_ID       1
38 #define GIC_INTERRUPT_CELL_FLAGS    2
39 #define GIC_INTERRUPT_TYPE_SPI      0
40 #define GIC_INTERRUPT_TYPE_PPI      1
41 #define GIC_INTERRUPT_BASE_SPI      32
42 #define GIC_INTERRUPT_BASE_PPI      16
43 
44 
45 extern void* gFDT;
46 
47 device_manager_info* gDeviceManager;
48 
49 extern fdt_bus_module_info gBusModule;
50 extern fdt_device_module_info gDeviceModule;
51 
52 
53 //#pragma mark -
54 
55 
56 struct fdt_bus {
57 	device_node* node;
58 	HashMap<HashKey32<int32>, device_node*> phandles;
59 };
60 
61 
62 struct fdt_device {
63 	device_node* node;
64 	device_node* bus;
65 };
66 
67 
68 struct fdt_interrupt_map_entry {
69 	uint32_t childAddr;
70 	uint32_t childIrq;
71 	uint32_t parentIrqCtrl;
72 	uint32_t parentIrq;
73 };
74 
75 
76 struct fdt_interrupt_map {
77 	uint32_t childAddrMask;
78 	uint32_t childIrqMask;
79 
80 	Vector<fdt_interrupt_map_entry> fInterruptMap;
81 };
82 
83 
84 static status_t
85 fdt_register_node(fdt_bus* bus, int node, device_node* parentDev,
86 	device_node*& curDev)
87 {
88 	TRACE("%s('%s', %p)\n", __func__, fdt_get_name(gFDT, node, NULL),
89 		parentDev);
90 
91 	const void* prop; int propLen;
92 	Vector<device_attr> attrs;
93 	int nameLen = 0;
94 	const char *name = fdt_get_name(gFDT, node, &nameLen);
95 
96 	if (name == NULL) {
97 		dprintf("%s ERROR: fdt_get_name: %s\n", __func__,
98 			fdt_strerror(nameLen));
99 		return B_ERROR;
100 	}
101 
102 	attrs.Add({ B_DEVICE_BUS, B_STRING_TYPE, {.string = "fdt"}});
103 	attrs.Add({ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
104 		{ .string = (strcmp(name, "") != 0) ? name : "Root" }});
105 	attrs.Add({ "fdt/node", B_UINT32_TYPE, {.ui32 = (uint32)node}});
106 	attrs.Add({ "fdt/name", B_STRING_TYPE, {.string = name}});
107 
108 	prop = fdt_getprop(gFDT, node, "device_type", &propLen);
109 	if (prop != NULL)
110 		attrs.Add({ "fdt/device_type", B_STRING_TYPE, { .string = (const char*)prop }});
111 
112 	prop = fdt_getprop(gFDT, node, "compatible", &propLen);
113 
114 	if (prop != NULL) {
115 		const char* propStr = (const char*)prop;
116 		const char* propEnd = propStr + propLen;
117 		while (propEnd - propStr > 0) {
118 			int curLen = strlen(propStr);
119 			attrs.Add({ "fdt/compatible", B_STRING_TYPE, { .string = propStr }});
120 			propStr += curLen + 1;
121 		}
122 	}
123 
124 	attrs.Add({});
125 
126 	status_t res = gDeviceManager->register_node(parentDev,
127 		"bus_managers/fdt/driver_v1", &attrs[0], NULL, &curDev);
128 
129 	if (res < B_OK)
130 		return res;
131 
132 	prop = fdt_getprop(gFDT, node, "phandle", &propLen);
133 
134 	if (prop != NULL)
135 		bus->phandles.Put(fdt32_to_cpu(*(uint32_t*)prop), curDev);
136 
137 	return B_OK;
138 }
139 
140 
141 static void
142 fdt_traverse(fdt_bus* bus, int &node, int &depth, device_node* parentDev)
143 {
144 	int curDepth = depth;
145 #if 0
146 	for (int i = 0; i < depth; i++) dprintf("  ");
147 	dprintf("node('%s')\n", fdt_get_name(gFDT, node, NULL));
148 #endif
149 	device_node* curDev;
150 	fdt_register_node(bus, node, parentDev, curDev);
151 
152 	node = fdt_next_node(gFDT, node, &depth);
153 	while (node >= 0 && depth == curDepth + 1) {
154 		fdt_traverse(bus, node, depth, curDev);
155 	}
156 }
157 
158 
159 //#pragma mark bus
160 
161 static int32
162 fdt_bus_std_ops(int32 op, ...)
163 {
164 	switch (op) {
165 		case B_MODULE_INIT:
166 			TRACE("fdt root init\n");
167 			return B_OK;
168 
169 		case B_MODULE_UNINIT:
170 			TRACE("fdt root uninit\n");
171 			return B_OK;
172 	}
173 
174 	return B_BAD_VALUE;
175 }
176 
177 
178 static float
179 fdt_bus_supports_device(device_node* parent)
180 {
181 	TRACE("fdt_bus_supports_device\n");
182 
183 	// make sure parent is really device root
184 	const char* bus;
185 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
186 		return B_ERROR;
187 
188 	if (strcmp(bus, "root"))
189 		return 0.0;
190 
191 	return 1.0;
192 }
193 
194 
195 static status_t
196 fdt_bus_register_device(device_node* parent)
197 {
198 	TRACE("+fdt_bus_register_device\n");
199 	struct ScopeExit {
200 		ScopeExit() {TRACE("-fdt_bus_register_device\n");}
201 	} scopeExit;
202 
203 	device_attr attrs[] = {
204 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "FDT"}},
205 		{B_DEVICE_FLAGS, B_UINT32_TYPE, {.ui32 = B_KEEP_DRIVER_LOADED}},
206 		{}
207 	};
208 
209 	return gDeviceManager->register_node(
210 		parent, "bus_managers/fdt/root/driver_v1", attrs, NULL, NULL);
211 }
212 
213 
214 static status_t
215 fdt_bus_init(device_node* node, void** cookie)
216 {
217 	TRACE("fdt_bus_init\n");
218 
219 	if (gFDT == NULL) {
220 		TRACE("FDT is NULL!\n");
221 		return B_DEVICE_NOT_FOUND;
222 	}
223 
224 	ObjectDeleter<fdt_bus> bus(new(std::nothrow) fdt_bus());
225 	if (!bus.IsSet())
226 		return B_NO_MEMORY;
227 
228 	// gFDT is stored in kernel_args and will be freed, so copy it to kernel heap.
229 	size_t size = fdt_totalsize(gFDT);
230 	void* newFDT = malloc(size);
231 	if (newFDT == NULL)
232 		return B_NO_MEMORY;
233 
234 	memcpy(newFDT, gFDT, size);
235 	gFDT = newFDT;
236 
237 	bus->node = node;
238 	*cookie = bus.Detach();
239 	return B_OK;
240 }
241 
242 
243 static void
244 fdt_bus_uninit(void* cookie)
245 {
246 	TRACE("fdt_bus_uninit\n");
247 
248 	ObjectDeleter<fdt_bus> bus((fdt_bus*)cookie);
249 }
250 
251 
252 static status_t
253 fdt_bus_register_child_devices(void* cookie)
254 {
255 	TRACE("fdt_bus_register_child_devices\n");
256 
257 	fdt_bus* bus = (fdt_bus*)cookie;
258 
259 	status_t res = gDeviceManager->publish_device(bus->node, "bus/fdt/blob",
260 		"bus_managers/fdt/device/v1");
261 	if (res < B_OK)
262 		return res;
263 
264 	int node = -1, depth = -1;
265 	node = fdt_next_node(gFDT, node, &depth);
266 	fdt_traverse(bus, node, depth, bus->node);
267 
268 	return B_OK;
269 }
270 
271 
272 device_node*
273 fdt_bus_node_by_phandle(fdt_bus* bus, int phandle)
274 {
275 	ASSERT(bus != NULL);
276 
277 	device_node** devNode;
278 	if (!bus->phandles.Get(phandle, devNode))
279 		return NULL;
280 
281 	return *devNode;
282 }
283 
284 
285 //#pragma mark device
286 
287 
288 static status_t
289 fdt_device_std_ops(int32 op, ...)
290 {
291 	switch (op) {
292 		case B_MODULE_INIT:
293 		case B_MODULE_UNINIT:
294 			return B_OK;
295 	}
296 
297 	return B_BAD_VALUE;
298 }
299 
300 
301 static status_t
302 fdt_device_init_driver(device_node* node, void** cookie)
303 {
304 	TRACE("fdt_device_init_driver()\n");
305 
306 	ObjectDeleter<fdt_device> dev(new(std::nothrow) fdt_device());
307 	if (!dev.IsSet())
308 		return B_NO_MEMORY;
309 
310 	dev->node = node;
311 
312 	// get bus from parent node
313 	DeviceNodePutter<&gDeviceManager> parent(
314 		gDeviceManager->get_parent_node(node));
315 	driver_module_info* parentModule;
316 	void* parentDev;
317 	ASSERT(gDeviceManager->get_driver(
318 		parent.Get(), &parentModule, &parentDev) >= B_OK);
319 	if (parentModule == (driver_module_info*)&gDeviceModule)
320 		dev->bus = ((fdt_device*)parentDev)->bus;
321 	else if (parentModule == (driver_module_info*)&gBusModule)
322 		dev->bus = parent.Get();
323 	else
324 		panic("bad parent node");
325 
326 	*cookie = dev.Detach();
327 	return B_OK;
328 }
329 
330 
331 static void
332 fdt_device_uninit_driver(void* cookie)
333 {
334 	TRACE("fdt_device_uninit_driver()\n");
335 	ObjectDeleter<fdt_device> dev((fdt_device*)cookie);
336 }
337 
338 
339 static status_t
340 fdt_device_register_child_devices(void* cookie)
341 {
342 	TRACE("fdt_device_register_child_devices()\n");
343 	return B_OK;
344 }
345 
346 
347 static device_node*
348 fdt_device_get_bus(fdt_device* dev)
349 {
350 	ASSERT(dev != NULL);
351 	return dev->bus;
352 }
353 
354 
355 static const char*
356 fdt_device_get_name(fdt_device* dev)
357 {
358 	ASSERT(dev != NULL);
359 
360 	uint32 fdtNode;
361 	ASSERT(gDeviceManager->get_attr_uint32(
362 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
363 
364 	return fdt_get_name(gFDT, (int)fdtNode, NULL);
365 }
366 
367 
368 static const void*
369 fdt_device_get_prop(fdt_device* dev, const char* name, int* len)
370 {
371 	ASSERT(dev != NULL);
372 
373 	uint32 fdtNode;
374 	ASSERT(gDeviceManager->get_attr_uint32(
375 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
376 
377 	return fdt_getprop(gFDT, (int)fdtNode, name, len);
378 }
379 
380 
381 static uint32
382 fdt_get_address_cells(const void* fdt, int node)
383 {
384 	uint32 res = 2;
385 
386 	int parent = fdt_parent_offset(fdt, node);
387 	if (parent < 0)
388 		return res;
389 
390 	uint32 *prop = (uint32*)fdt_getprop(fdt, parent, "#address-cells", NULL);
391 	if (prop == NULL)
392 		return res;
393 
394 	res = fdt32_to_cpu(*prop);
395 	return res;
396 }
397 
398 
399 static uint32
400 fdt_get_size_cells(const void* fdt, int node)
401 {
402 	uint32 res = 1;
403 
404 	int parent = fdt_parent_offset(fdt, node);
405 	if (parent < 0)
406 		return res;
407 
408 	uint32 *prop = (uint32*)fdt_getprop(fdt, parent, "#size-cells", NULL);
409 	if (prop == NULL)
410 		return res;
411 
412 	res = fdt32_to_cpu(*prop);
413 	return res;
414 }
415 
416 
417 static bool
418 fdt_device_get_reg(fdt_device* dev, uint32 ord, uint64* regs, uint64* len)
419 {
420 	ASSERT(dev != NULL);
421 
422 	uint32 fdtNode;
423 	ASSERT(gDeviceManager->get_attr_uint32(
424 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
425 
426 	int propLen;
427 	const void* prop = fdt_getprop(gFDT, (int)fdtNode, "reg", &propLen);
428 	if (prop == NULL)
429 		return false;
430 
431 	uint32 addressCells = fdt_get_address_cells(gFDT, fdtNode);
432 	uint32 sizeCells = fdt_get_size_cells(gFDT, fdtNode);
433 	size_t entrySize = 4 * (addressCells + sizeCells);
434 
435 	if ((ord + 1) * entrySize > (uint32)propLen)
436 		return false;
437 
438 	const void* addressPtr = (const uint8*)prop + ord * entrySize;
439 	const void* sizePtr = (const uint32*)addressPtr + addressCells;
440 
441 	switch (addressCells) {
442 		case 1:
443 			*regs = fdt32_to_cpu(*(const uint32*)addressPtr);
444 			break;
445 		case 2:
446 			*regs = fdt64_to_cpu(*(const uint64*)addressPtr);
447 			break;
448 		default:
449 			return false;
450 	}
451 	switch (sizeCells) {
452 		case 1:
453 			*len = fdt32_to_cpu(*(const uint32*)sizePtr);
454 			break;
455 		case 2:
456 			*len = fdt64_to_cpu(*(const uint64*)sizePtr);
457 			break;
458 		default:
459 			return false;
460 	}
461 
462 	return true;
463 }
464 
465 
466 static uint32
467 fdt_get_interrupt_parent(fdt_device* dev, int node)
468 {
469 	while (node >= 0) {
470 		uint32* prop;
471 		int propLen;
472 		prop = (uint32*)fdt_getprop(gFDT, node, "interrupt-parent", &propLen);
473 		if (prop != NULL && propLen == 4) {
474 			return fdt32_to_cpu(*prop);
475 		}
476 
477 		node = fdt_parent_offset(gFDT, node);
478 	}
479 
480 	return 0;
481 }
482 
483 
484 static uint32
485 fdt_get_interrupt_cells(uint32 interrupt_parent_phandle)
486 {
487 	if (interrupt_parent_phandle > 0) {
488 		int node = fdt_node_offset_by_phandle(gFDT, interrupt_parent_phandle);
489 		if (node >= 0) {
490 			uint32* prop;
491 			int propLen;
492 			prop  = (uint32*)fdt_getprop(gFDT, node, "#interrupt-cells", &propLen);
493 			if (prop != NULL && propLen == 4) {
494 				return fdt32_to_cpu(*prop);
495 			}
496 		}
497 	}
498 	return 1;
499 }
500 
501 
502 static bool
503 fdt_device_get_interrupt(fdt_device* dev, uint32 index,
504 	device_node** interruptController, uint64* interrupt)
505 {
506 	ASSERT(dev != NULL);
507 
508 	uint32 fdtNode;
509 	ASSERT(gDeviceManager->get_attr_uint32(
510 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
511 
512 	int propLen;
513 	const uint32 *prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended",
514 		&propLen);
515 	if (prop == NULL) {
516 		uint32 interruptParent = fdt_get_interrupt_parent(dev, fdtNode);
517 		uint32 interruptCells = fdt_get_interrupt_cells(interruptParent);
518 
519 		prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts",
520 			&propLen);
521 		if (prop == NULL)
522 			return false;
523 
524 		if ((index + 1) * interruptCells * sizeof(uint32) > (uint32)propLen)
525 			return false;
526 
527 		uint32 offset = interruptCells * index;
528 		uint32 interruptNumber = 0;
529 
530 		if ((interruptCells == 1) || (interruptCells == 2)) {
531 			 interruptNumber = fdt32_to_cpu(*(prop + offset));
532 		} else if (interruptCells == 3) {
533 			uint32 interruptType = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_TYPE]);
534 			interruptNumber = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_ID]);
535 
536 			if (interruptType == GIC_INTERRUPT_TYPE_SPI)
537 				interruptNumber += GIC_INTERRUPT_BASE_SPI;
538 			else if (interruptType == GIC_INTERRUPT_TYPE_PPI)
539 				interruptNumber += GIC_INTERRUPT_BASE_PPI;
540 		} else {
541 			panic("unsupported interruptCells");
542 		}
543 
544 		if (interrupt != NULL)
545 			*interrupt = interruptNumber;
546 
547 		if (interruptController != NULL && interruptParent != 0) {
548 			fdt_bus* bus;
549 			ASSERT(gDeviceManager->get_driver(dev->bus, NULL, (void**)&bus) >= B_OK);
550 			*interruptController = fdt_bus_node_by_phandle(bus, interruptParent);
551 		}
552 
553 		return true;
554 	}
555 
556 	if ((index + 1) * 8 > (uint32)propLen)
557 		return false;
558 
559 	if (interruptController != NULL) {
560 		uint32 phandle = fdt32_to_cpu(*(prop + 2 * index));
561 
562 		fdt_bus* bus;
563 		ASSERT(gDeviceManager->get_driver(
564 			dev->bus, NULL, (void**)&bus) >= B_OK);
565 
566 		*interruptController = fdt_bus_node_by_phandle(bus, phandle);
567 	}
568 
569 	if (interrupt != NULL)
570 		*interrupt = fdt32_to_cpu(*(prop + 2 * index + 1));
571 
572 	return true;
573 }
574 
575 
576 static struct fdt_interrupt_map *
577 fdt_device_get_interrupt_map(struct fdt_device* dev)
578 {
579 	int fdtNode;
580 	ASSERT(gDeviceManager->get_attr_uint32(
581 		dev->node, "fdt/node", (uint32*)&fdtNode, false) >= B_OK);
582 
583 	ObjectDeleter<struct fdt_interrupt_map> interrupt_map(new struct fdt_interrupt_map());
584 
585 	int intMapMaskLen;
586 	const void* intMapMask = fdt_getprop(gFDT, fdtNode, "interrupt-map-mask",
587 		&intMapMaskLen);
588 
589 	if (intMapMask == NULL || intMapMaskLen != 4 * 4) {
590 		dprintf("  interrupt-map-mask property not found or invalid\n");
591 		return NULL;
592 	}
593 
594 	interrupt_map->childAddrMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 0));
595 	interrupt_map->childIrqMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 3));
596 
597 	int intMapLen;
598 	const void* intMapAddr = fdt_getprop(gFDT, fdtNode, "interrupt-map", &intMapLen);
599 	if (intMapAddr == NULL) {
600 		dprintf("  interrupt-map property not found\n");
601 		return NULL;
602 	}
603 
604 	int addressCells = 3;
605 	int interruptCells = 1;
606 	int phandleCells = 1;
607 
608 	const void *property;
609 
610 	property = fdt_getprop(gFDT, fdtNode, "#address-cells", NULL);
611 	if (property != NULL)
612 		addressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
613 
614 	property = fdt_getprop(gFDT, fdtNode, "#interrupt-cells", NULL);
615 	if (property != NULL)
616 		interruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
617 
618 	uint32_t *it = (uint32_t*)intMapAddr;
619 	while ((uint8_t*)it - (uint8_t*)intMapAddr < intMapLen) {
620 		struct fdt_interrupt_map_entry irqEntry;
621 
622 		irqEntry.childAddr = B_BENDIAN_TO_HOST_INT32(*it);
623 		it += addressCells;
624 
625 		irqEntry.childIrq = B_BENDIAN_TO_HOST_INT32(*it);
626 		it += interruptCells;
627 
628 		irqEntry.parentIrqCtrl = B_BENDIAN_TO_HOST_INT32(*it);
629 		it += phandleCells;
630 
631 		int parentAddressCells = 0;
632 		int parentInterruptCells = 1;
633 
634 		int interruptParent = fdt_node_offset_by_phandle(gFDT, irqEntry.parentIrqCtrl);
635 		if (interruptParent >= 0) {
636 			property = fdt_getprop(gFDT, interruptParent, "#address-cells", NULL);
637 			if (property != NULL)
638 				parentAddressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
639 
640 			property = fdt_getprop(gFDT, interruptParent, "#interrupt-cells", NULL);
641 			if (property != NULL)
642 				parentInterruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
643 		}
644 
645 		it += parentAddressCells;
646 
647 		if ((parentInterruptCells == 1) || (parentInterruptCells == 2)) {
648 			irqEntry.parentIrq = B_BENDIAN_TO_HOST_INT32(*it);
649 		} else if (parentInterruptCells == 3) {
650 			uint32 interruptType = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_TYPE]);
651 			uint32 interruptNumber = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_ID]);
652 
653 			if (interruptType == GIC_INTERRUPT_TYPE_SPI)
654 				irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_SPI;
655 			else if (interruptType == GIC_INTERRUPT_TYPE_PPI)
656 				irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_PPI;
657 			else
658 				irqEntry.parentIrq = interruptNumber;
659 		}
660 		it += parentInterruptCells;
661 
662 		interrupt_map->fInterruptMap.PushBack(irqEntry);
663 	}
664 
665 	return interrupt_map.Detach();
666 }
667 
668 
669 static void
670 fdt_device_print_interrupt_map(struct fdt_interrupt_map* interruptMap)
671 {
672 	if (interruptMap == NULL)
673 		return;
674 
675 	dprintf("interrupt_map_mask: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n",
676 		interruptMap->childAddrMask, interruptMap->childIrqMask);
677 	dprintf("interrupt_map:\n");
678 
679 	for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin();
680 		it != interruptMap->fInterruptMap.End();
681 		it++) {
682 
683 		dprintf("childAddr=0x%08" PRIx32 ", childIrq=%" PRIu32 ", parentIrqCtrl=%" PRIu32 ", parentIrq=%" PRIu32 "\n",
684 			it->childAddr, it->childIrq, it->parentIrqCtrl, it->parentIrq);
685 	}
686 }
687 
688 
689 static uint32
690 fdt_device_lookup_interrupt_map(struct fdt_interrupt_map* interruptMap, uint32 childAddr, uint32 childIrq)
691 {
692 	if (interruptMap == NULL)
693 		return 0xffffffff;
694 
695 	childAddr &= interruptMap->childAddrMask;
696 	childIrq &= interruptMap->childIrqMask;
697 
698 	for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin();
699 			it != interruptMap->fInterruptMap.End(); it++) {
700 		if ((it->childAddr == childAddr) && (it->childIrq == childIrq))
701 			return it->parentIrq;
702 	}
703 
704 	return 0xffffffff;
705 }
706 
707 
708 //#pragma mark devfs node
709 
710 
711 static status_t
712 fdt_devfs_node_read(void *cookie, off_t pos, void *buffer, size_t *_length)
713 {
714 	if (pos < 0)
715 		return B_BAD_VALUE;
716 
717 	size_t size = fdt_totalsize(gFDT);
718 	if ((uint64)pos >= size) {
719 		*_length = 0;
720 		return B_OK;
721 	}
722 	size_t readSize = *_length;
723 	if (pos + readSize > size)
724 		readSize = size - pos;
725 
726 	status_t res = user_memcpy(buffer, (uint8*)gFDT + pos, readSize);
727 	if (res < B_OK)
728 		return res;
729 
730 	*_length = readSize;
731 	return B_OK;
732 }
733 
734 
735 //#pragma mark -
736 
737 fdt_bus_module_info gBusModule = {
738 	{
739 		{
740 			"bus_managers/fdt/root/driver_v1",
741 			0,
742 			fdt_bus_std_ops
743 		},
744 		fdt_bus_supports_device,
745 		fdt_bus_register_device,
746 		fdt_bus_init,
747 		fdt_bus_uninit,
748 		fdt_bus_register_child_devices,
749 		NULL,	// rescan devices
750 		NULL,	// device removed
751 	},
752 	fdt_bus_node_by_phandle,
753 };
754 
755 
756 fdt_device_module_info gDeviceModule = {
757 	{
758 		{
759 			"bus_managers/fdt/driver_v1",
760 			0,
761 			fdt_device_std_ops
762 		},
763 
764 		NULL,		// supports device
765 		NULL,		// register device (our parent registered us)
766 		fdt_device_init_driver,
767 		fdt_device_uninit_driver,
768 		fdt_device_register_child_devices,
769 		NULL,		// rescan devices
770 		NULL,		// device removed
771 	},
772 	fdt_device_get_bus,
773 	fdt_device_get_name,
774 	fdt_device_get_prop,
775 	fdt_device_get_reg,
776 	fdt_device_get_interrupt,
777 	fdt_device_get_interrupt_map,
778 	fdt_device_print_interrupt_map,
779 	fdt_device_lookup_interrupt_map,
780 };
781 
782 
783 device_module_info gDevfsNodeModule = {
784 	.info = {
785 			.name = "bus_managers/fdt/device/v1"
786 	},
787 	.init_device = [](void *driverCookie, void **_deviceCookie) {
788 		*_deviceCookie = NULL;
789 		return B_OK;
790 	},
791 	.uninit_device = [](void *deviceCookie) {},
792 	.open = [](void *deviceCookie, const char *path, int openMode, void **_cookie) {
793 		return B_OK;
794 	},
795 	.close = [](void *cookie) {
796 		return B_OK;
797 	},
798 	.free = [](void *cookie) {
799 		return B_OK;
800 	},
801 	.read = fdt_devfs_node_read,
802 	.control = [](void *cookie, uint32 op, void *buffer, size_t length) {
803 		return B_DEV_INVALID_IOCTL;
804 	},
805 };
806 
807 
808 module_info* modules[] = {
809 	(module_info*)&gBusModule,
810 	(module_info*)&gDeviceModule,
811 	(module_info*)&gDevfsNodeModule,
812 	NULL
813 };
814 
815 module_dependency module_dependencies[] = {
816 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
817 	{ NULL }
818 };
819