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