xref: /haiku/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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 	bus->node = node;
229 	*cookie = bus.Detach();
230 	return B_OK;
231 }
232 
233 
234 static void
235 fdt_bus_uninit(void* cookie)
236 {
237 	TRACE("fdt_bus_uninit\n");
238 
239 	ObjectDeleter<fdt_bus> bus((fdt_bus*)cookie);
240 }
241 
242 
243 static status_t
244 fdt_bus_register_child_devices(void* cookie)
245 {
246 	TRACE("fdt_bus_register_child_devices\n");
247 
248 	fdt_bus* bus = (fdt_bus*)cookie;
249 
250 	int node = -1, depth = -1;
251 	node = fdt_next_node(gFDT, node, &depth);
252 	fdt_traverse(bus, node, depth, bus->node);
253 
254 	return B_OK;
255 }
256 
257 
258 device_node*
259 fdt_bus_node_by_phandle(fdt_bus* bus, int phandle)
260 {
261 	ASSERT(bus != NULL);
262 
263 	device_node** devNode;
264 	if (!bus->phandles.Get(phandle, devNode))
265 		return NULL;
266 
267 	return *devNode;
268 }
269 
270 
271 //#pragma mark device
272 
273 
274 static status_t
275 fdt_device_std_ops(int32 op, ...)
276 {
277 	switch (op) {
278 		case B_MODULE_INIT:
279 		case B_MODULE_UNINIT:
280 			return B_OK;
281 	}
282 
283 	return B_BAD_VALUE;
284 }
285 
286 
287 static status_t
288 fdt_device_init_driver(device_node* node, void** cookie)
289 {
290 	TRACE("fdt_device_init_driver()\n");
291 
292 	ObjectDeleter<fdt_device> dev(new(std::nothrow) fdt_device());
293 	if (!dev.IsSet())
294 		return B_NO_MEMORY;
295 
296 	dev->node = node;
297 
298 	// get bus from parent node
299 	DeviceNodePutter<&gDeviceManager> parent(
300 		gDeviceManager->get_parent_node(node));
301 	driver_module_info* parentModule;
302 	void* parentDev;
303 	ASSERT(gDeviceManager->get_driver(
304 		parent.Get(), &parentModule, &parentDev) >= B_OK);
305 	if (parentModule == (driver_module_info*)&gDeviceModule)
306 		dev->bus = ((fdt_device*)parentDev)->bus;
307 	else if (parentModule == (driver_module_info*)&gBusModule)
308 		dev->bus = parent.Get();
309 	else
310 		panic("bad parent node");
311 
312 	*cookie = dev.Detach();
313 	return B_OK;
314 }
315 
316 
317 static void
318 fdt_device_uninit_driver(void* cookie)
319 {
320 	TRACE("fdt_device_uninit_driver()\n");
321 	ObjectDeleter<fdt_device> dev((fdt_device*)cookie);
322 }
323 
324 
325 static status_t
326 fdt_device_register_child_devices(void* cookie)
327 {
328 	TRACE("fdt_device_register_child_devices()\n");
329 	return B_OK;
330 }
331 
332 
333 static device_node*
334 fdt_device_get_bus(fdt_device* dev)
335 {
336 	ASSERT(dev != NULL);
337 	return dev->bus;
338 }
339 
340 
341 static const char*
342 fdt_device_get_name(fdt_device* dev)
343 {
344 	ASSERT(dev != NULL);
345 
346 	uint32 fdtNode;
347 	ASSERT(gDeviceManager->get_attr_uint32(
348 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
349 
350 	return fdt_get_name(gFDT, (int)fdtNode, NULL);
351 }
352 
353 
354 static const void*
355 fdt_device_get_prop(fdt_device* dev, const char* name, int* len)
356 {
357 	ASSERT(dev != NULL);
358 
359 	uint32 fdtNode;
360 	ASSERT(gDeviceManager->get_attr_uint32(
361 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
362 
363 	return fdt_getprop(gFDT, (int)fdtNode, name, len);
364 }
365 
366 
367 static uint32
368 fdt_get_address_cells(const void* fdt, int node)
369 {
370 	uint32 res = 2;
371 
372 	int parent = fdt_parent_offset(fdt, node);
373 	if (parent < 0)
374 		return res;
375 
376 	uint32 *prop = (uint32*)fdt_getprop(fdt, parent, "#address-cells", NULL);
377 	if (prop == NULL)
378 		return res;
379 
380 	res = fdt32_to_cpu(*prop);
381 	return res;
382 }
383 
384 
385 static uint32
386 fdt_get_size_cells(const void* fdt, int node)
387 {
388 	uint32 res = 1;
389 
390 	int parent = fdt_parent_offset(fdt, node);
391 	if (parent < 0)
392 		return res;
393 
394 	uint32 *prop = (uint32*)fdt_getprop(fdt, parent, "#size-cells", NULL);
395 	if (prop == NULL)
396 		return res;
397 
398 	res = fdt32_to_cpu(*prop);
399 	return res;
400 }
401 
402 
403 static bool
404 fdt_device_get_reg(fdt_device* dev, uint32 ord, uint64* regs, uint64* len)
405 {
406 	ASSERT(dev != NULL);
407 
408 	uint32 fdtNode;
409 	ASSERT(gDeviceManager->get_attr_uint32(
410 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
411 
412 	int propLen;
413 	const void* prop = fdt_getprop(gFDT, (int)fdtNode, "reg", &propLen);
414 	if (prop == NULL)
415 		return false;
416 
417 	uint32 addressCells = fdt_get_address_cells(gFDT, fdtNode);
418 	uint32 sizeCells = fdt_get_size_cells(gFDT, fdtNode);
419 	size_t entrySize = 4 * (addressCells + sizeCells);
420 
421 	if ((ord + 1) * entrySize > (uint32)propLen)
422 		return false;
423 
424 	const void* addressPtr = (const uint8*)prop + ord * entrySize;
425 	const void* sizePtr = (const uint32*)addressPtr + addressCells;
426 
427 	switch (addressCells) {
428 		case 1:
429 			*regs = fdt32_to_cpu(*(const uint32*)addressPtr);
430 			break;
431 		case 2:
432 			*regs = fdt64_to_cpu(*(const uint64*)addressPtr);
433 			break;
434 		default:
435 			return false;
436 	}
437 	switch (sizeCells) {
438 		case 1:
439 			*len = fdt32_to_cpu(*(const uint32*)sizePtr);
440 			break;
441 		case 2:
442 			*len = fdt64_to_cpu(*(const uint64*)sizePtr);
443 			break;
444 		default:
445 			return false;
446 	}
447 
448 	return true;
449 }
450 
451 
452 static uint32
453 fdt_get_interrupt_parent(fdt_device* dev, int node)
454 {
455 	while (node >= 0) {
456 		uint32* prop;
457 		int propLen;
458 		prop = (uint32*)fdt_getprop(gFDT, node, "interrupt-parent", &propLen);
459 		if (prop != NULL && propLen == 4) {
460 			return fdt32_to_cpu(*prop);
461 		}
462 
463 		node = fdt_parent_offset(gFDT, node);
464 	}
465 
466 	return 0;
467 }
468 
469 
470 static uint32
471 fdt_get_interrupt_cells(uint32 interrupt_parent_phandle)
472 {
473 	if (interrupt_parent_phandle > 0) {
474 		int node = fdt_node_offset_by_phandle(gFDT, interrupt_parent_phandle);
475 		if (node >= 0) {
476 			uint32* prop;
477 			int propLen;
478 			prop  = (uint32*)fdt_getprop(gFDT, node, "#interrupt-cells", &propLen);
479 			if (prop != NULL && propLen == 4) {
480 				return fdt32_to_cpu(*prop);
481 			}
482 		}
483 	}
484 	return 1;
485 }
486 
487 
488 static bool
489 fdt_device_get_interrupt(fdt_device* dev, uint32 index,
490 	device_node** interruptController, uint64* interrupt)
491 {
492 	ASSERT(dev != NULL);
493 
494 	uint32 fdtNode;
495 	ASSERT(gDeviceManager->get_attr_uint32(
496 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
497 
498 	int propLen;
499 	const uint32 *prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended",
500 		&propLen);
501 	if (prop == NULL) {
502 		uint32 interruptParent = fdt_get_interrupt_parent(dev, fdtNode);
503 		uint32 interruptCells = fdt_get_interrupt_cells(interruptParent);
504 
505 		prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts",
506 			&propLen);
507 		if (prop == NULL)
508 			return false;
509 
510 		if ((index + 1) * interruptCells * sizeof(uint32) > (uint32)propLen)
511 			return false;
512 
513 		uint32 offset = interruptCells * index;
514 		uint32 interruptNumber = 0;
515 
516 		if ((interruptCells == 1) || (interruptCells == 2)) {
517 			 interruptNumber = fdt32_to_cpu(*(prop + offset));
518 		} else if (interruptCells == 3) {
519 			uint32 interruptType = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_TYPE]);
520 			interruptNumber = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_ID]);
521 
522 			if (interruptType == GIC_INTERRUPT_TYPE_SPI)
523 				interruptNumber += GIC_INTERRUPT_BASE_SPI;
524 			else if (interruptType == GIC_INTERRUPT_TYPE_PPI)
525 				interruptNumber += GIC_INTERRUPT_BASE_PPI;
526 		} else {
527 			panic("unsupported interruptCells");
528 		}
529 
530 		if (interrupt != NULL)
531 			*interrupt = interruptNumber;
532 
533 		if (interruptController != NULL && interruptParent != 0) {
534 			fdt_bus* bus;
535 			ASSERT(gDeviceManager->get_driver(dev->bus, NULL, (void**)&bus) >= B_OK);
536 			*interruptController = fdt_bus_node_by_phandle(bus, interruptParent);
537 		}
538 
539 		return true;
540 	}
541 
542 	if ((index + 1) * 8 > (uint32)propLen)
543 		return false;
544 
545 	if (interruptController != NULL) {
546 		uint32 phandle = fdt32_to_cpu(*(prop + 2 * index));
547 
548 		fdt_bus* bus;
549 		ASSERT(gDeviceManager->get_driver(
550 			dev->bus, NULL, (void**)&bus) >= B_OK);
551 
552 		*interruptController = fdt_bus_node_by_phandle(bus, phandle);
553 	}
554 
555 	if (interrupt != NULL)
556 		*interrupt = fdt32_to_cpu(*(prop + 2 * index + 1));
557 
558 	return true;
559 }
560 
561 
562 static struct fdt_interrupt_map *
563 fdt_device_get_interrupt_map(struct fdt_device* dev)
564 {
565 	int fdtNode;
566 	ASSERT(gDeviceManager->get_attr_uint32(
567 		dev->node, "fdt/node", (uint32*)&fdtNode, false) >= B_OK);
568 
569 	ObjectDeleter<struct fdt_interrupt_map> interrupt_map(new struct fdt_interrupt_map());
570 
571 	int intMapMaskLen;
572 	const void* intMapMask = fdt_getprop(gFDT, fdtNode, "interrupt-map-mask",
573 		&intMapMaskLen);
574 
575 	if (intMapMask == NULL || intMapMaskLen != 4 * 4) {
576 		dprintf("  interrupt-map-mask property not found or invalid\n");
577 		return NULL;
578 	}
579 
580 	interrupt_map->childAddrMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 0));
581 	interrupt_map->childIrqMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 3));
582 
583 	int intMapLen;
584 	const void* intMapAddr = fdt_getprop(gFDT, fdtNode, "interrupt-map", &intMapLen);
585 	if (intMapAddr == NULL) {
586 		dprintf("  interrupt-map property not found\n");
587 		return NULL;
588 	}
589 
590 	int addressCells = 3;
591 	int interruptCells = 1;
592 	int phandleCells = 1;
593 
594 	const void *property;
595 
596 	property = fdt_getprop(gFDT, fdtNode, "#address-cells", NULL);
597 	if (property != NULL)
598 		addressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
599 
600 	property = fdt_getprop(gFDT, fdtNode, "#interrupt-cells", NULL);
601 	if (property != NULL)
602 		interruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
603 
604 	uint32_t *it = (uint32_t*)intMapAddr;
605 	while ((uint8_t*)it - (uint8_t*)intMapAddr < intMapLen) {
606 		struct fdt_interrupt_map_entry irqEntry;
607 
608 		irqEntry.childAddr = B_BENDIAN_TO_HOST_INT32(*it);
609 		it += addressCells;
610 
611 		irqEntry.childIrq = B_BENDIAN_TO_HOST_INT32(*it);
612 		it += interruptCells;
613 
614 		irqEntry.parentIrqCtrl = B_BENDIAN_TO_HOST_INT32(*it);
615 		it += phandleCells;
616 
617 		int parentAddressCells = 0;
618 		int parentInterruptCells = 1;
619 
620 		int interruptParent = fdt_node_offset_by_phandle(gFDT, irqEntry.parentIrqCtrl);
621 		if (interruptParent >= 0) {
622 			property = fdt_getprop(gFDT, interruptParent, "#address-cells", NULL);
623 			if (property != NULL)
624 				parentAddressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
625 
626 			property = fdt_getprop(gFDT, interruptParent, "#interrupt-cells", NULL);
627 			if (property != NULL)
628 				parentInterruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
629 		}
630 
631 		it += parentAddressCells;
632 
633 		if ((parentInterruptCells == 1) || (parentInterruptCells == 2)) {
634 			irqEntry.parentIrq = B_BENDIAN_TO_HOST_INT32(*it);
635 		} else if (parentInterruptCells == 3) {
636 			uint32 interruptType = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_TYPE]);
637 			uint32 interruptNumber = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_ID]);
638 
639 			if (interruptType == GIC_INTERRUPT_TYPE_SPI)
640 				irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_SPI;
641 			else if (interruptType == GIC_INTERRUPT_TYPE_PPI)
642 				irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_PPI;
643 			else
644 				irqEntry.parentIrq = interruptNumber;
645 		}
646 		it += parentInterruptCells;
647 
648 		interrupt_map->fInterruptMap.PushBack(irqEntry);
649 	}
650 
651 	return interrupt_map.Detach();
652 }
653 
654 
655 static void
656 fdt_device_print_interrupt_map(struct fdt_interrupt_map* interruptMap)
657 {
658 	if (interruptMap == NULL)
659 		return;
660 
661 	dprintf("interrupt_map_mask: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n",
662 		interruptMap->childAddrMask, interruptMap->childIrqMask);
663 	dprintf("interrupt_map:\n");
664 
665 	for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin();
666 		it != interruptMap->fInterruptMap.End();
667 		it++) {
668 
669 		dprintf("childAddr=0x%08" PRIx32 ", childIrq=%" PRIu32 ", parentIrqCtrl=%" PRIu32 ", parentIrq=%" PRIu32 "\n",
670 			it->childAddr, it->childIrq, it->parentIrqCtrl, it->parentIrq);
671 	}
672 }
673 
674 
675 static uint32
676 fdt_device_lookup_interrupt_map(struct fdt_interrupt_map* interruptMap, uint32 childAddr, uint32 childIrq)
677 {
678 	if (interruptMap == NULL)
679 		return 0xffffffff;
680 
681 	childAddr &= interruptMap->childAddrMask;
682 	childIrq &= interruptMap->childIrqMask;
683 
684 	for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin();
685 			it != interruptMap->fInterruptMap.End(); it++) {
686 		if ((it->childAddr == childAddr) && (it->childIrq == childIrq))
687 			return it->parentIrq;
688 	}
689 
690 	return 0xffffffff;
691 }
692 
693 
694 //#pragma mark -
695 
696 fdt_bus_module_info gBusModule = {
697 	{
698 		{
699 			"bus_managers/fdt/root/driver_v1",
700 			0,
701 			fdt_bus_std_ops
702 		},
703 		fdt_bus_supports_device,
704 		fdt_bus_register_device,
705 		fdt_bus_init,
706 		fdt_bus_uninit,
707 		fdt_bus_register_child_devices,
708 		NULL,	// rescan devices
709 		NULL,	// device removed
710 	},
711 	fdt_bus_node_by_phandle,
712 };
713 
714 
715 fdt_device_module_info gDeviceModule = {
716 	{
717 		{
718 			"bus_managers/fdt/driver_v1",
719 			0,
720 			fdt_device_std_ops
721 		},
722 
723 		NULL,		// supports device
724 		NULL,		// register device (our parent registered us)
725 		fdt_device_init_driver,
726 		fdt_device_uninit_driver,
727 		fdt_device_register_child_devices,
728 		NULL,		// rescan devices
729 		NULL,		// device removed
730 	},
731 	fdt_device_get_bus,
732 	fdt_device_get_name,
733 	fdt_device_get_prop,
734 	fdt_device_get_reg,
735 	fdt_device_get_interrupt,
736 	fdt_device_get_interrupt_map,
737 	fdt_device_print_interrupt_map,
738 	fdt_device_lookup_interrupt_map,
739 };
740 
741 
742 module_info* modules[] = {
743 	(module_info*)&gBusModule,
744 	(module_info*)&gDeviceModule,
745 	NULL
746 };
747 
748 module_dependency module_dependencies[] = {
749 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
750 	{ NULL }
751 };
752