1 /* 2 * Copyright 2002-2011, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "legacy_drivers.h" 8 9 #include <dirent.h> 10 #include <errno.h> 11 #include <new> 12 #include <stdio.h> 13 14 #include <FindDirectory.h> 15 #include <image.h> 16 #include <NodeMonitor.h> 17 18 #include <boot_device.h> 19 #include <boot/kernel_args.h> 20 #include <elf.h> 21 #include <find_directory_private.h> 22 #include <fs/devfs.h> 23 #include <fs/KPath.h> 24 #include <fs/node_monitor.h> 25 #include <Notifications.h> 26 #include <safemode.h> 27 #include <util/DoublyLinkedList.h> 28 #include <util/OpenHashTable.h> 29 #include <util/Stack.h> 30 #include <vfs.h> 31 32 #include "AbstractModuleDevice.h" 33 #include "devfs_private.h" 34 35 36 //#define TRACE_LEGACY_DRIVERS 37 #ifdef TRACE_LEGACY_DRIVERS 38 # define TRACE(x) dprintf x 39 #else 40 # define TRACE(x) 41 #endif 42 43 #define DRIVER_HASH_SIZE 16 44 45 46 namespace { 47 48 struct legacy_driver; 49 50 class LegacyDevice : public AbstractModuleDevice, 51 public DoublyLinkedListLinkImpl<LegacyDevice> { 52 public: 53 LegacyDevice(legacy_driver* driver, 54 const char* path, device_hooks* hooks); 55 virtual ~LegacyDevice(); 56 57 status_t InitCheck() const; 58 59 virtual status_t InitDevice(); 60 virtual void UninitDevice(); 61 62 virtual void Removed(); 63 64 void SetHooks(device_hooks* hooks); 65 66 legacy_driver* Driver() const { return fDriver; } 67 const char* Path() const { return fPath; } 68 device_hooks* Hooks() const { return fHooks; } 69 70 virtual status_t Open(const char* path, int openMode, 71 void** _cookie); 72 virtual status_t Select(void* cookie, uint8 event, selectsync* sync); 73 74 bool Republished() const { return fRepublished; } 75 void SetRepublished(bool republished) 76 { fRepublished = republished; } 77 78 void SetRemovedFromParent(bool removed) 79 { fRemovedFromParent = removed; } 80 81 private: 82 legacy_driver* fDriver; 83 const char* fPath; 84 device_hooks* fHooks; 85 bool fRepublished; 86 bool fRemovedFromParent; 87 }; 88 89 typedef DoublyLinkedList<LegacyDevice> DeviceList; 90 91 struct legacy_driver { 92 legacy_driver* next; 93 const char* path; 94 const char* name; 95 dev_t device; 96 ino_t node; 97 timespec last_modified; 98 image_id image; 99 uint32 devices_used; 100 bool binary_updated; 101 int32 priority; 102 DeviceList devices; 103 104 // driver image information 105 int32 api_version; 106 device_hooks* (*find_device)(const char *); 107 const char** (*publish_devices)(void); 108 status_t (*uninit_driver)(void); 109 status_t (*uninit_hardware)(void); 110 }; 111 112 113 enum driver_event_type { 114 kAddDriver, 115 kRemoveDriver, 116 kAddWatcher, 117 kRemoveWatcher 118 }; 119 120 struct driver_event : DoublyLinkedListLinkImpl<driver_event> { 121 driver_event(driver_event_type _type) : type(_type) {} 122 123 struct ref { 124 dev_t device; 125 ino_t node; 126 }; 127 128 driver_event_type type; 129 union { 130 char path[B_PATH_NAME_LENGTH]; 131 ref node; 132 }; 133 }; 134 135 typedef DoublyLinkedList<driver_event> DriverEventList; 136 137 138 struct driver_entry : DoublyLinkedListLinkImpl<driver_entry> { 139 char* path; 140 dev_t device; 141 ino_t node; 142 int32 busses; 143 }; 144 145 typedef DoublyLinkedList<driver_entry> DriverEntryList; 146 147 148 struct node_entry : DoublyLinkedListLinkImpl<node_entry> { 149 }; 150 151 typedef DoublyLinkedList<node_entry> NodeList; 152 153 154 struct directory_node_entry { 155 directory_node_entry* hash_link; 156 ino_t node; 157 }; 158 159 struct DirectoryNodeHashDefinition { 160 typedef ino_t* KeyType; 161 typedef directory_node_entry ValueType; 162 163 size_t HashKey(ino_t* key) const 164 { return _Hash(*key); } 165 size_t Hash(directory_node_entry* entry) const 166 { return _Hash(entry->node); } 167 bool Compare(ino_t* key, directory_node_entry* entry) const 168 { return *key == entry->node; } 169 directory_node_entry*& 170 GetLink(directory_node_entry* entry) const 171 { return entry->hash_link; } 172 173 uint32 _Hash(ino_t node) const 174 { return (uint32)(node >> 32) + (uint32)node; } 175 }; 176 177 typedef BOpenHashTable<DirectoryNodeHashDefinition> DirectoryNodeHash; 178 179 class DirectoryIterator { 180 public: 181 DirectoryIterator(const char *path, 182 const char *subPath = NULL, bool recursive = false); 183 ~DirectoryIterator(); 184 185 void SetTo(const char *path, const char *subPath = NULL, 186 bool recursive = false); 187 188 status_t GetNext(KPath &path, struct stat &stat); 189 const char* CurrentName() const { return fCurrentName; } 190 191 void Unset(); 192 void AddPath(const char *path, const char *subPath = NULL); 193 194 private: 195 Stack<KPath*> fPaths; 196 bool fRecursive; 197 DIR* fDirectory; 198 KPath* fBasePath; 199 const char* fCurrentName; 200 }; 201 202 203 class DirectoryWatcher : public NotificationListener { 204 public: 205 DirectoryWatcher(); 206 virtual ~DirectoryWatcher(); 207 208 virtual void EventOccurred(NotificationService& service, 209 const KMessage* event); 210 }; 211 212 class DriverWatcher : public NotificationListener { 213 public: 214 DriverWatcher(); 215 virtual ~DriverWatcher(); 216 217 virtual void EventOccurred(NotificationService& service, 218 const KMessage* event); 219 }; 220 221 222 struct DriverHash { 223 typedef const char* KeyType; 224 typedef legacy_driver ValueType; 225 226 size_t HashKey(KeyType key) const 227 { 228 return hash_hash_string(key); 229 } 230 231 size_t Hash(ValueType* driver) const 232 { 233 return HashKey(driver->name); 234 } 235 236 bool Compare(KeyType key, ValueType* driver) const 237 { 238 return strcmp(driver->name, key) == 0; 239 } 240 241 ValueType*& GetLink(ValueType* value) const 242 { 243 return value->next; 244 } 245 }; 246 247 typedef BOpenHashTable<DriverHash> DriverTable; 248 249 250 } // unnamed namespace 251 252 253 static status_t unload_driver(legacy_driver *driver); 254 static status_t load_driver(legacy_driver *driver); 255 256 257 static DriverWatcher sDriverWatcher; 258 static int32 sDriverEventsPending; 259 static DriverEventList sDriverEvents; 260 static mutex sDriverEventsLock = MUTEX_INITIALIZER("driver events"); 261 // inner lock, protects the sDriverEvents list only 262 static DirectoryWatcher sDirectoryWatcher; 263 static DirectoryNodeHash sDirectoryNodeHash; 264 static recursive_lock sLock; 265 static bool sWatching; 266 267 static DriverTable* sDriverHash; 268 269 270 // #pragma mark - driver private 271 272 273 /*! Collects all published devices of a driver, compares them to what the 274 driver would publish now, and then publishes/unpublishes the devices 275 as needed. 276 If the driver does not publish any devices anymore, it is unloaded. 277 */ 278 static status_t 279 republish_driver(legacy_driver* driver) 280 { 281 if (driver->image < 0) { 282 // The driver is not yet loaded - go through the normal load procedure 283 return load_driver(driver); 284 } 285 286 // mark all devices 287 DeviceList::Iterator iterator = driver->devices.GetIterator(); 288 while (LegacyDevice* device = iterator.Next()) { 289 device->SetRepublished(false); 290 } 291 292 // now ask the driver for it's currently published devices 293 const char** devicePaths = driver->publish_devices(); 294 295 int32 exported = 0; 296 for (; devicePaths != NULL && devicePaths[0]; devicePaths++) { 297 LegacyDevice* device; 298 299 iterator = driver->devices.GetIterator(); 300 while ((device = iterator.Next()) != NULL) { 301 if (!strncmp(device->Path(), devicePaths[0], B_PATH_NAME_LENGTH)) { 302 // mark device as republished 303 device->SetRepublished(true); 304 exported++; 305 break; 306 } 307 } 308 309 device_hooks* hooks = driver->find_device(devicePaths[0]); 310 if (hooks == NULL) 311 continue; 312 313 if (device != NULL) { 314 // update hooks 315 device->SetHooks(hooks); 316 continue; 317 } 318 319 // the device was not present before -> publish it now 320 TRACE(("devfs: publishing new device \"%s\"\n", devicePaths[0])); 321 device = new(std::nothrow) LegacyDevice(driver, devicePaths[0], hooks); 322 if (device != NULL && device->InitCheck() == B_OK 323 && devfs_publish_device(devicePaths[0], device) == B_OK) { 324 driver->devices.Add(device); 325 exported++; 326 } else 327 delete device; 328 } 329 330 // remove all devices that weren't republished 331 iterator = driver->devices.GetIterator(); 332 while (LegacyDevice* device = iterator.Next()) { 333 if (device->Republished()) 334 continue; 335 336 TRACE(("devfs: unpublishing no more present \"%s\"\n", device->Path())); 337 iterator.Remove(); 338 device->SetRemovedFromParent(true); 339 340 devfs_unpublish_device(device, true); 341 } 342 343 if (exported == 0 && driver->devices_used == 0) { 344 TRACE(("devfs: driver \"%s\" does not publish any more nodes and is " 345 "unloaded\n", driver->path)); 346 unload_driver(driver); 347 } 348 349 return B_OK; 350 } 351 352 353 static status_t 354 load_driver(legacy_driver *driver) 355 { 356 status_t (*init_hardware)(void); 357 status_t (*init_driver)(void); 358 status_t status; 359 360 driver->binary_updated = false; 361 362 // load the module 363 image_id image = driver->image; 364 if (image < 0) { 365 image = load_kernel_add_on(driver->path); 366 if (image < 0) 367 return image; 368 } 369 370 // For a valid device driver the following exports are required 371 372 int32 *apiVersion; 373 if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, 374 (void **)&apiVersion) == B_OK) { 375 #if B_CUR_DRIVER_API_VERSION != 2 376 // just in case someone decides to bump up the api version 377 #error Add checks here for new vs old api version! 378 #endif 379 if (*apiVersion > B_CUR_DRIVER_API_VERSION) { 380 dprintf("devfs: \"%s\" api_version %" B_PRId32 " not handled\n", 381 driver->name, *apiVersion); 382 status = B_BAD_VALUE; 383 goto error1; 384 } 385 if (*apiVersion < 1) { 386 dprintf("devfs: \"%s\" api_version invalid\n", driver->name); 387 status = B_BAD_VALUE; 388 goto error1; 389 } 390 391 driver->api_version = *apiVersion; 392 } else 393 dprintf("devfs: \"%s\" api_version missing\n", driver->name); 394 395 if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, 396 (void **)&driver->publish_devices) != B_OK 397 || get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, 398 (void **)&driver->find_device) != B_OK) { 399 dprintf("devfs: \"%s\" mandatory driver symbol(s) missing!\n", 400 driver->name); 401 status = B_BAD_VALUE; 402 goto error1; 403 } 404 405 // Init the driver 406 407 if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT, 408 (void **)&init_hardware) == B_OK 409 && (status = init_hardware()) != B_OK) { 410 TRACE(("%s: init_hardware() failed: %s\n", driver->name, 411 strerror(status))); 412 status = ENXIO; 413 goto error1; 414 } 415 416 if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT, 417 (void **)&init_driver) == B_OK 418 && (status = init_driver()) != B_OK) { 419 TRACE(("%s: init_driver() failed: %s\n", driver->name, 420 strerror(status))); 421 status = ENXIO; 422 goto error2; 423 } 424 425 // resolve and cache those for the driver unload code 426 if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT, 427 (void **)&driver->uninit_driver) != B_OK) 428 driver->uninit_driver = NULL; 429 if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT, 430 (void **)&driver->uninit_hardware) != B_OK) 431 driver->uninit_hardware = NULL; 432 433 // The driver has successfully been initialized, now we can 434 // finally publish its device entries 435 436 driver->image = image; 437 return republish_driver(driver); 438 439 error2: 440 if (driver->uninit_hardware) 441 driver->uninit_hardware(); 442 443 error1: 444 if (driver->image < 0) { 445 unload_kernel_add_on(image); 446 driver->image = status; 447 } 448 449 return status; 450 } 451 452 453 static status_t 454 unload_driver(legacy_driver *driver) 455 { 456 if (driver->image < 0) { 457 // driver is not currently loaded 458 return B_NO_INIT; 459 } 460 461 if (driver->uninit_driver) 462 driver->uninit_driver(); 463 464 if (driver->uninit_hardware) 465 driver->uninit_hardware(); 466 467 unload_kernel_add_on(driver->image); 468 driver->image = -1; 469 driver->binary_updated = false; 470 driver->find_device = NULL; 471 driver->publish_devices = NULL; 472 driver->uninit_driver = NULL; 473 driver->uninit_hardware = NULL; 474 475 return B_OK; 476 } 477 478 479 /*! Unpublishes all devices belonging to the \a driver. */ 480 static void 481 unpublish_driver(legacy_driver *driver) 482 { 483 while (LegacyDevice* device = driver->devices.RemoveHead()) { 484 device->SetRemovedFromParent(true); 485 devfs_unpublish_device(device, true); 486 } 487 } 488 489 490 static void 491 change_driver_watcher(dev_t device, ino_t node, bool add) 492 { 493 if (device == -1) 494 return; 495 496 driver_event* event = new (std::nothrow) driver_event( 497 add ? kAddWatcher : kRemoveWatcher); 498 if (event == NULL) 499 return; 500 501 event->node.device = device; 502 event->node.node = node; 503 504 MutexLocker _(sDriverEventsLock); 505 sDriverEvents.Add(event); 506 507 atomic_add(&sDriverEventsPending, 1); 508 } 509 510 511 static int32 512 get_priority(const char* path) 513 { 514 // TODO: would it be better to initialize a static structure here 515 // using find_directory()? 516 const directory_which whichPath[] = { 517 B_BEOS_DIRECTORY, 518 B_SYSTEM_NONPACKAGED_DIRECTORY, 519 B_USER_DIRECTORY 520 }; 521 KPath pathBuffer; 522 523 for (uint32 index = 0; index < sizeof(whichPath) / sizeof(whichPath[0]); 524 index++) { 525 if (__find_directory(whichPath[index], gBootDevice, false, 526 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { 527 pathBuffer.UnlockBuffer(); 528 if (!strncmp(pathBuffer.Path(), path, pathBuffer.BufferSize())) 529 return index; 530 } else 531 pathBuffer.UnlockBuffer(); 532 } 533 534 return -1; 535 } 536 537 538 static const char * 539 get_leaf(const char *path) 540 { 541 const char *name = strrchr(path, '/'); 542 if (name == NULL) 543 return path; 544 545 return name + 1; 546 } 547 548 549 static legacy_driver * 550 find_driver(dev_t device, ino_t node) 551 { 552 DriverTable::Iterator iterator(sDriverHash); 553 while (iterator.HasNext()) { 554 legacy_driver *driver = iterator.Next(); 555 if (driver->device == device && driver->node == node) 556 return driver; 557 } 558 559 return NULL; 560 } 561 562 563 static status_t 564 add_driver(const char *path, image_id image) 565 { 566 // Check if we already know this driver 567 568 struct stat stat; 569 if (image >= 0) { 570 // The image ID should be a small number and hopefully the boot FS 571 // doesn't use small negative values -- if it is inode based, we should 572 // be relatively safe. 573 stat.st_dev = -1; 574 stat.st_ino = -1; 575 } else { 576 if (::stat(path, &stat) != 0) 577 return errno; 578 } 579 580 int32 priority = get_priority(path); 581 582 RecursiveLocker _(sLock); 583 584 legacy_driver *driver = sDriverHash->Lookup(get_leaf(path)); 585 if (driver != NULL) { 586 // we know this driver 587 if (strcmp(driver->path, path) != 0) { 588 // TODO: do properly, but for now we just update the path if it 589 // isn't the same anymore so rescanning of drivers will work in 590 // case this driver was loaded so early that it has a boot module 591 // path and not a proper driver path 592 free((char*)driver->path); 593 driver->path = strdup(path); 594 driver->name = get_leaf(driver->path); 595 driver->binary_updated = true; 596 } 597 598 // TODO: check if this driver is a different one and has precendence 599 // (ie. common supersedes system). 600 //dprintf("new driver has priority %ld, old %ld\n", priority, driver->priority); 601 if (priority >= driver->priority) { 602 driver->binary_updated = true; 603 return B_OK; 604 } 605 606 // TODO: test for changes here and/or via node monitoring and reload 607 // the driver if necessary 608 if (driver->image < B_OK) 609 return driver->image; 610 611 return B_OK; 612 } 613 614 // we don't know this driver, create a new entry for it 615 616 driver = (legacy_driver *)malloc(sizeof(legacy_driver)); 617 if (driver == NULL) 618 return B_NO_MEMORY; 619 620 driver->path = strdup(path); 621 if (driver->path == NULL) { 622 free(driver); 623 return B_NO_MEMORY; 624 } 625 626 driver->name = get_leaf(driver->path); 627 driver->device = stat.st_dev; 628 driver->node = stat.st_ino; 629 driver->image = image; 630 driver->last_modified = stat.st_mtim; 631 driver->devices_used = 0; 632 driver->binary_updated = false; 633 driver->priority = priority; 634 635 driver->api_version = 1; 636 driver->find_device = NULL; 637 driver->publish_devices = NULL; 638 driver->uninit_driver = NULL; 639 driver->uninit_hardware = NULL; 640 new(&driver->devices) DeviceList; 641 642 sDriverHash->Insert(driver); 643 if (stat.st_dev > 0) 644 change_driver_watcher(stat.st_dev, stat.st_ino, true); 645 646 // Even if loading the driver fails - its entry will stay with us 647 // so that we don't have to go through it again 648 return load_driver(driver); 649 } 650 651 652 /*! This is no longer part of the public kernel API, so we just export the 653 symbol 654 */ 655 extern "C" status_t load_driver_symbols(const char *driverName); 656 status_t 657 load_driver_symbols(const char *driverName) 658 { 659 // This is done globally for the whole kernel via the settings file. 660 // We don't have to do anything here. 661 662 return B_OK; 663 } 664 665 666 static status_t 667 reload_driver(legacy_driver *driver) 668 { 669 dprintf("devfs: reload driver \"%s\" (%" B_PRIdDEV ", %" B_PRIdINO ")\n", 670 driver->name, driver->device, driver->node); 671 672 unload_driver(driver); 673 674 struct stat stat; 675 if (::stat(driver->path, &stat) == 0 676 && (stat.st_dev != driver->device || stat.st_ino != driver->node)) { 677 // The driver file has been changed, so we need to update its listener 678 change_driver_watcher(driver->device, driver->node, false); 679 680 driver->device = stat.st_dev; 681 driver->node = stat.st_ino; 682 683 change_driver_watcher(driver->device, driver->node, true); 684 } 685 686 status_t status = load_driver(driver); 687 if (status != B_OK) 688 unpublish_driver(driver); 689 690 return status; 691 } 692 693 694 static void 695 handle_driver_events(void */*_fs*/, int /*iteration*/) 696 { 697 if (atomic_and(&sDriverEventsPending, 0) == 0) 698 return; 699 700 // something happened, let's see what it was 701 702 while (true) { 703 MutexLocker eventLocker(sDriverEventsLock); 704 705 driver_event* event = sDriverEvents.RemoveHead(); 706 if (event == NULL) 707 break; 708 709 eventLocker.Unlock(); 710 TRACE(("driver event %p, type %d\n", event, event->type)); 711 712 switch (event->type) { 713 case kAddDriver: 714 { 715 // Add new drivers 716 RecursiveLocker locker(sLock); 717 TRACE((" add driver %p\n", event->path)); 718 719 legacy_driver* driver = sDriverHash->Lookup( 720 get_leaf(event->path)); 721 if (driver == NULL) 722 legacy_driver_add(event->path); 723 else if (get_priority(event->path) >= driver->priority) 724 driver->binary_updated = true; 725 break; 726 } 727 728 case kRemoveDriver: 729 { 730 // Mark removed drivers as updated 731 RecursiveLocker locker(sLock); 732 TRACE((" remove driver %p\n", event->path)); 733 734 legacy_driver* driver = sDriverHash->Lookup( 735 get_leaf(event->path)); 736 if (driver != NULL 737 && get_priority(event->path) >= driver->priority) 738 driver->binary_updated = true; 739 break; 740 } 741 742 case kAddWatcher: 743 TRACE((" add watcher %ld:%lld\n", event->node.device, 744 event->node.node)); 745 add_node_listener(event->node.device, event->node.node, 746 B_WATCH_STAT | B_WATCH_NAME, sDriverWatcher); 747 break; 748 749 case kRemoveWatcher: 750 TRACE((" remove watcher %ld:%lld\n", event->node.device, 751 event->node.node)); 752 remove_node_listener(event->node.device, event->node.node, 753 sDriverWatcher); 754 break; 755 } 756 757 delete event; 758 } 759 760 // Reload updated drivers 761 762 RecursiveLocker locker(sLock); 763 764 DriverTable::Iterator iterator(sDriverHash); 765 while (iterator.HasNext()) { 766 legacy_driver *driver = iterator.Next(); 767 768 if (!driver->binary_updated || driver->devices_used != 0) 769 continue; 770 771 // try to reload the driver 772 reload_driver(driver); 773 } 774 775 locker.Unlock(); 776 } 777 778 779 // #pragma mark - DriverWatcher 780 781 782 DriverWatcher::DriverWatcher() 783 { 784 } 785 786 787 DriverWatcher::~DriverWatcher() 788 { 789 } 790 791 792 void 793 DriverWatcher::EventOccurred(NotificationService& service, 794 const KMessage* event) 795 { 796 int32 opcode = event->GetInt32("opcode", -1); 797 if (opcode != B_STAT_CHANGED 798 || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0) 799 return; 800 801 RecursiveLocker locker(sLock); 802 803 legacy_driver* driver = find_driver(event->GetInt32("device", -1), 804 event->GetInt64("node", 0)); 805 if (driver == NULL) 806 return; 807 808 driver->binary_updated = true; 809 810 if (driver->devices_used == 0) { 811 // trigger a reload of the driver 812 atomic_add(&sDriverEventsPending, 1); 813 } else { 814 // driver is in use right now 815 dprintf("devfs: changed driver \"%s\" is still in use\n", driver->name); 816 } 817 } 818 819 820 static void 821 dump_driver(legacy_driver* driver) 822 { 823 kprintf("DEVFS DRIVER: %p\n", driver); 824 kprintf(" name: %s\n", driver->name); 825 kprintf(" path: %s\n", driver->path); 826 kprintf(" image: %" B_PRId32 "\n", driver->image); 827 kprintf(" device: %" B_PRIdDEV "\n", driver->device); 828 kprintf(" node: %" B_PRIdINO "\n", driver->node); 829 kprintf(" last modified: %" B_PRIdTIME ".%ld\n", driver->last_modified.tv_sec, 830 driver->last_modified.tv_nsec); 831 kprintf(" devs used: %" B_PRIu32 "\n", driver->devices_used); 832 kprintf(" devs published: %" B_PRId32 "\n", driver->devices.Count()); 833 kprintf(" binary updated: %d\n", driver->binary_updated); 834 kprintf(" priority: %" B_PRId32 "\n", driver->priority); 835 kprintf(" api version: %" B_PRId32 "\n", driver->api_version); 836 kprintf(" hooks: find_device %p, publish_devices %p\n" 837 " uninit_driver %p, uninit_hardware %p\n", 838 driver->find_device, driver->publish_devices, driver->uninit_driver, 839 driver->uninit_hardware); 840 } 841 842 843 static int 844 dump_device(int argc, char** argv) 845 { 846 if (argc < 2 || !strcmp(argv[1], "--help")) { 847 kprintf("usage: %s [device]\n", argv[0]); 848 return 0; 849 } 850 851 LegacyDevice* device = (LegacyDevice*)parse_expression(argv[1]); 852 853 kprintf("LEGACY DEVICE: %p\n", device); 854 kprintf(" path: %s\n", device->Path()); 855 kprintf(" hooks: %p\n", device->Hooks()); 856 device_hooks* hooks = device->Hooks(); 857 kprintf(" close() %p\n", hooks->close); 858 kprintf(" free() %p\n", hooks->free); 859 kprintf(" control() %p\n", hooks->control); 860 kprintf(" read() %p\n", hooks->read); 861 kprintf(" write() %p\n", hooks->write); 862 kprintf(" select() %p\n", hooks->select); 863 kprintf(" deselect() %p\n", hooks->deselect); 864 dump_driver(device->Driver()); 865 866 return 0; 867 } 868 869 870 static int 871 dump_driver(int argc, char** argv) 872 { 873 if (argc < 2) { 874 // print list of all drivers 875 kprintf("address image used publ. pri name\n"); 876 DriverTable::Iterator iterator(sDriverHash); 877 while (iterator.HasNext()) { 878 legacy_driver* driver = iterator.Next(); 879 880 kprintf("%p %5" B_PRId32 " %3" B_PRIu32 " %5" B_PRId32 " %c " 881 "%3" B_PRId32 " %s\n", driver, 882 driver->image < 0 ? -1 : driver->image, 883 driver->devices_used, driver->devices.Count(), 884 driver->binary_updated ? 'U' : ' ', driver->priority, 885 driver->name); 886 } 887 888 return 0; 889 } 890 891 if (!strcmp(argv[1], "--help")) { 892 kprintf("usage: %s [name]\n", argv[0]); 893 return 0; 894 } 895 896 legacy_driver* driver = sDriverHash->Lookup(argv[1]); 897 if (driver == NULL) { 898 kprintf("Driver named \"%s\" not found.\n", argv[1]); 899 return 0; 900 } 901 902 dump_driver(driver); 903 return 0; 904 } 905 906 907 // #pragma mark - 908 909 910 DirectoryIterator::DirectoryIterator(const char* path, const char* subPath, 911 bool recursive) 912 : 913 fDirectory(NULL), 914 fBasePath(NULL), 915 fCurrentName(NULL) 916 { 917 SetTo(path, subPath, recursive); 918 } 919 920 921 DirectoryIterator::~DirectoryIterator() 922 { 923 Unset(); 924 } 925 926 927 void 928 DirectoryIterator::SetTo(const char* path, const char* subPath, bool recursive) 929 { 930 Unset(); 931 fRecursive = recursive; 932 933 if (path == NULL) { 934 // add default paths 935 const directory_which whichPath[] = { 936 B_USER_NONPACKAGED_ADDONS_DIRECTORY, 937 B_USER_ADDONS_DIRECTORY, 938 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, 939 B_BEOS_ADDONS_DIRECTORY 940 }; 941 KPath pathBuffer; 942 943 bool disableUserAddOns = get_safemode_boolean( 944 B_SAFEMODE_DISABLE_USER_ADD_ONS, false); 945 946 for (uint32 i = 0; i < sizeof(whichPath) / sizeof(whichPath[0]); i++) { 947 if (i < 2 && disableUserAddOns) 948 continue; 949 950 if (__find_directory(whichPath[i], gBootDevice, true, 951 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { 952 pathBuffer.UnlockBuffer(); 953 pathBuffer.Append("kernel"); 954 AddPath(pathBuffer.Path(), subPath); 955 } else 956 pathBuffer.UnlockBuffer(); 957 } 958 } else 959 AddPath(path, subPath); 960 } 961 962 963 status_t 964 DirectoryIterator::GetNext(KPath& path, struct stat& stat) 965 { 966 next_directory: 967 while (fDirectory == NULL) { 968 delete fBasePath; 969 fBasePath = NULL; 970 971 if (!fPaths.Pop(&fBasePath)) 972 return B_ENTRY_NOT_FOUND; 973 974 fDirectory = opendir(fBasePath->Path()); 975 } 976 977 next_entry: 978 struct dirent* dirent = readdir(fDirectory); 979 if (dirent == NULL) { 980 // get over to next directory on the stack 981 closedir(fDirectory); 982 fDirectory = NULL; 983 984 goto next_directory; 985 } 986 987 if (!strcmp(dirent->d_name, "..") || !strcmp(dirent->d_name, ".")) 988 goto next_entry; 989 990 fCurrentName = dirent->d_name; 991 992 path.SetTo(fBasePath->Path()); 993 path.Append(fCurrentName); 994 995 if (::stat(path.Path(), &stat) != 0) 996 goto next_entry; 997 998 if (S_ISDIR(stat.st_mode) && fRecursive) { 999 KPath *nextPath = new(nothrow) KPath(path); 1000 if (!nextPath) 1001 return B_NO_MEMORY; 1002 if (fPaths.Push(nextPath) != B_OK) 1003 return B_NO_MEMORY; 1004 1005 goto next_entry; 1006 } 1007 1008 return B_OK; 1009 } 1010 1011 1012 void 1013 DirectoryIterator::Unset() 1014 { 1015 if (fDirectory != NULL) { 1016 closedir(fDirectory); 1017 fDirectory = NULL; 1018 } 1019 1020 delete fBasePath; 1021 fBasePath = NULL; 1022 1023 KPath *path; 1024 while (fPaths.Pop(&path)) 1025 delete path; 1026 } 1027 1028 1029 void 1030 DirectoryIterator::AddPath(const char* basePath, const char* subPath) 1031 { 1032 KPath *path = new(nothrow) KPath(basePath); 1033 if (!path) 1034 panic("out of memory"); 1035 if (subPath != NULL) 1036 path->Append(subPath); 1037 1038 fPaths.Push(path); 1039 } 1040 1041 1042 // #pragma mark - 1043 1044 1045 DirectoryWatcher::DirectoryWatcher() 1046 { 1047 } 1048 1049 1050 DirectoryWatcher::~DirectoryWatcher() 1051 { 1052 } 1053 1054 1055 void 1056 DirectoryWatcher::EventOccurred(NotificationService& service, 1057 const KMessage* event) 1058 { 1059 int32 opcode = event->GetInt32("opcode", -1); 1060 dev_t device = event->GetInt32("device", -1); 1061 ino_t directory = event->GetInt64("directory", -1); 1062 const char *name = event->GetString("name", NULL); 1063 1064 if (opcode == B_ENTRY_MOVED) { 1065 // Determine whether it's a move within, out of, or into one 1066 // of our watched directories. 1067 ino_t from = event->GetInt64("from directory", -1); 1068 ino_t to = event->GetInt64("to directory", -1); 1069 if (sDirectoryNodeHash.Lookup(&from) == NULL) { 1070 directory = to; 1071 opcode = B_ENTRY_CREATED; 1072 } else if (sDirectoryNodeHash.Lookup(&to) == NULL) { 1073 directory = from; 1074 opcode = B_ENTRY_REMOVED; 1075 } else { 1076 // Move within, don't do anything for now 1077 // TODO: adjust driver priority if necessary 1078 return; 1079 } 1080 } 1081 1082 KPath path(B_PATH_NAME_LENGTH + 1); 1083 if (path.InitCheck() != B_OK || vfs_entry_ref_to_path(device, directory, 1084 name, true, path.LockBuffer(), path.BufferSize()) != B_OK) 1085 return; 1086 1087 path.UnlockBuffer(); 1088 1089 dprintf("driver \"%s\" %s\n", path.Leaf(), 1090 opcode == B_ENTRY_CREATED ? "added" : "removed"); 1091 1092 driver_event* driverEvent = new(std::nothrow) driver_event( 1093 opcode == B_ENTRY_CREATED ? kAddDriver : kRemoveDriver); 1094 if (driverEvent == NULL) 1095 return; 1096 1097 strlcpy(driverEvent->path, path.Path(), sizeof(driverEvent->path)); 1098 1099 MutexLocker _(sDriverEventsLock); 1100 sDriverEvents.Add(driverEvent); 1101 atomic_add(&sDriverEventsPending, 1); 1102 } 1103 1104 1105 // #pragma mark - 1106 1107 1108 static void 1109 start_watching(const char *base, const char *sub) 1110 { 1111 KPath path(base); 1112 path.Append(sub); 1113 1114 // TODO: create missing directories? 1115 struct stat stat; 1116 if (::stat(path.Path(), &stat) != 0) 1117 return; 1118 1119 add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, 1120 sDirectoryWatcher); 1121 1122 directory_node_entry *entry = new(std::nothrow) directory_node_entry; 1123 if (entry != NULL) { 1124 entry->node = stat.st_ino; 1125 sDirectoryNodeHash.Insert(entry); 1126 } 1127 } 1128 1129 1130 static struct driver_entry* 1131 new_driver_entry(const char* path, dev_t device, ino_t node) 1132 { 1133 driver_entry* entry = (driver_entry*)malloc(sizeof(driver_entry)); 1134 if (entry == NULL) 1135 return NULL; 1136 1137 entry->path = strdup(path); 1138 if (entry->path == NULL) { 1139 free(entry); 1140 return NULL; 1141 } 1142 1143 entry->device = device; 1144 entry->node = node; 1145 entry->busses = 0; 1146 return entry; 1147 } 1148 1149 1150 /*! Iterates over the given list and tries to load all drivers in that list. 1151 The list is emptied and freed during the traversal. 1152 */ 1153 static status_t 1154 try_drivers(DriverEntryList& list) 1155 { 1156 while (true) { 1157 driver_entry* entry = list.RemoveHead(); 1158 if (entry == NULL) 1159 break; 1160 1161 image_id image = load_kernel_add_on(entry->path); 1162 if (image >= 0) { 1163 // check if it's an old-style driver 1164 if (legacy_driver_add(entry->path) == B_OK) { 1165 // we have a driver 1166 dprintf("loaded driver %s\n", entry->path); 1167 } 1168 1169 unload_kernel_add_on(image); 1170 } 1171 1172 free(entry->path); 1173 free(entry); 1174 } 1175 1176 return B_OK; 1177 } 1178 1179 1180 static status_t 1181 probe_for_drivers(const char *type) 1182 { 1183 TRACE(("probe_for_drivers(type = %s)\n", type)); 1184 1185 if (gBootDevice < 0) 1186 return B_OK; 1187 1188 DriverEntryList drivers; 1189 1190 // build list of potential drivers for that type 1191 1192 DirectoryIterator iterator(NULL, type, false); 1193 struct stat stat; 1194 KPath path; 1195 1196 while (iterator.GetNext(path, stat) == B_OK) { 1197 if (S_ISDIR(stat.st_mode)) { 1198 add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, 1199 sDirectoryWatcher); 1200 1201 directory_node_entry *entry 1202 = new(std::nothrow) directory_node_entry; 1203 if (entry != NULL) { 1204 entry->node = stat.st_ino; 1205 sDirectoryNodeHash.Insert(entry); 1206 } 1207 1208 // We need to make sure that drivers in ie. "audio/raw/" can 1209 // be found as well - therefore, we must make sure that "audio" 1210 // exists on /dev. 1211 1212 size_t length = strlen("drivers/dev"); 1213 if (strncmp(type, "drivers/dev", length)) 1214 continue; 1215 1216 path.SetTo(type); 1217 path.Append(iterator.CurrentName()); 1218 devfs_publish_directory(path.Path() + length + 1); 1219 continue; 1220 } 1221 1222 driver_entry *entry = new_driver_entry(path.Path(), stat.st_dev, 1223 stat.st_ino); 1224 if (entry == NULL) 1225 return B_NO_MEMORY; 1226 1227 TRACE(("found potential driver: %s\n", path.Path())); 1228 drivers.Add(entry); 1229 } 1230 1231 if (drivers.IsEmpty()) 1232 return B_OK; 1233 1234 // ToDo: do something with the remaining drivers... :) 1235 try_drivers(drivers); 1236 return B_OK; 1237 } 1238 1239 1240 // #pragma mark - LegacyDevice 1241 1242 1243 LegacyDevice::LegacyDevice(legacy_driver* driver, const char* path, 1244 device_hooks* hooks) 1245 : 1246 fDriver(driver), 1247 fRepublished(true), 1248 fRemovedFromParent(false) 1249 { 1250 fDeviceModule = (device_module_info*)malloc(sizeof(device_module_info)); 1251 if (fDeviceModule != NULL) 1252 memset(fDeviceModule, 0, sizeof(device_module_info)); 1253 1254 fDeviceData = this; 1255 fPath = strdup(path); 1256 1257 SetHooks(hooks); 1258 } 1259 1260 1261 LegacyDevice::~LegacyDevice() 1262 { 1263 free(fDeviceModule); 1264 free((char*)fPath); 1265 } 1266 1267 1268 status_t 1269 LegacyDevice::InitCheck() const 1270 { 1271 return fDeviceModule != NULL && fPath != NULL ? B_OK : B_NO_MEMORY; 1272 } 1273 1274 1275 status_t 1276 LegacyDevice::InitDevice() 1277 { 1278 RecursiveLocker _(sLock); 1279 1280 if (fInitialized++ > 0) 1281 return B_OK; 1282 1283 if (fDriver != NULL && fDriver->devices_used == 0 1284 && (fDriver->image < 0 || fDriver->binary_updated)) { 1285 status_t status = reload_driver(fDriver); 1286 if (status < B_OK) 1287 return status; 1288 } 1289 1290 if (fDriver != NULL) 1291 fDriver->devices_used++; 1292 1293 return B_OK; 1294 } 1295 1296 1297 void 1298 LegacyDevice::UninitDevice() 1299 { 1300 RecursiveLocker _(sLock); 1301 1302 if (fInitialized-- > 1) 1303 return; 1304 1305 if (fDriver != NULL) { 1306 if (--fDriver->devices_used == 0 && fDriver->devices.IsEmpty()) 1307 unload_driver(fDriver); 1308 fDriver = NULL; 1309 } 1310 } 1311 1312 1313 void 1314 LegacyDevice::Removed() 1315 { 1316 RecursiveLocker _(sLock); 1317 1318 if (!fRemovedFromParent && fDriver != NULL) 1319 fDriver->devices.Remove(this); 1320 1321 delete this; 1322 } 1323 1324 1325 void 1326 LegacyDevice::SetHooks(device_hooks* hooks) 1327 { 1328 // TODO: setup compatibility layer! 1329 fHooks = hooks; 1330 1331 fDeviceModule->close = hooks->close; 1332 fDeviceModule->free = hooks->free; 1333 fDeviceModule->control = hooks->control; 1334 fDeviceModule->read = hooks->read; 1335 fDeviceModule->write = hooks->write; 1336 1337 if (fDriver == NULL || fDriver->api_version >= 2) { 1338 // According to Be newsletter, vol II, issue 36, 1339 // version 2 added readv/writev, which we don't support, but also 1340 // select/deselect. 1341 if (hooks->select != NULL) { 1342 // Note we set the module's select to a non-null value to indicate 1343 // that we have select. HasSelect() will therefore return the 1344 // correct answer. As Select() is virtual our compatibility 1345 // version below is going to be called though, that redirects to 1346 // the proper select hook, so it is ok to set it to an invalid 1347 // address here. 1348 fDeviceModule->select = (status_t (*)(void*, uint8, selectsync*))~0; 1349 } 1350 1351 fDeviceModule->deselect = hooks->deselect; 1352 } 1353 } 1354 1355 1356 status_t 1357 LegacyDevice::Open(const char* path, int openMode, void** _cookie) 1358 { 1359 return Hooks()->open(path, openMode, _cookie); 1360 } 1361 1362 1363 status_t 1364 LegacyDevice::Select(void* cookie, uint8 event, selectsync* sync) 1365 { 1366 return Hooks()->select(cookie, event, 0, sync); 1367 } 1368 1369 1370 // #pragma mark - kernel private API 1371 1372 1373 extern "C" void 1374 legacy_driver_add_preloaded(kernel_args* args) 1375 { 1376 // NOTE: This function does not exit in case of error, since it 1377 // needs to unload the images then. Also the return code of 1378 // the path operations is kept separate from the add_driver() 1379 // success, so that even if add_driver() fails for one driver, it 1380 // is still tried for the other drivers. 1381 // NOTE: The initialization success of the path objects is implicitely 1382 // checked by the immediately following functions. 1383 KPath basePath; 1384 status_t status = __find_directory(B_BEOS_ADDONS_DIRECTORY, 1385 gBootDevice, false, basePath.LockBuffer(), basePath.BufferSize()); 1386 if (status != B_OK) { 1387 dprintf("legacy_driver_add_preloaded: find_directory() failed: " 1388 "%s\n", strerror(status)); 1389 } 1390 basePath.UnlockBuffer(); 1391 if (status == B_OK) 1392 status = basePath.Append("kernel"); 1393 if (status != B_OK) { 1394 dprintf("legacy_driver_add_preloaded: constructing base driver " 1395 "path failed: %s\n", strerror(status)); 1396 return; 1397 } 1398 1399 struct preloaded_image* image; 1400 for (image = args->preloaded_images; image != NULL; image = image->next) { 1401 if (image->is_module || image->id < 0) 1402 continue; 1403 1404 KPath imagePath(basePath); 1405 status = imagePath.Append(image->name); 1406 1407 // try to add the driver 1408 TRACE(("legacy_driver_add_preloaded: adding driver %s\n", 1409 imagePath.Path())); 1410 1411 if (status == B_OK) 1412 status = add_driver(imagePath.Path(), image->id); 1413 if (status != B_OK) { 1414 dprintf("legacy_driver_add_preloaded: Failed to add \"%s\": %s\n", 1415 (char *)image->name, strerror(status)); 1416 unload_kernel_add_on(image->id); 1417 } 1418 } 1419 } 1420 1421 1422 extern "C" status_t 1423 legacy_driver_add(const char* path) 1424 { 1425 return add_driver(path, -1); 1426 } 1427 1428 1429 extern "C" status_t 1430 legacy_driver_publish(const char *path, device_hooks *hooks) 1431 { 1432 // we don't have a driver, just publish the hooks 1433 LegacyDevice* device = new(std::nothrow) LegacyDevice(NULL, path, hooks); 1434 if (device == NULL) 1435 return B_NO_MEMORY; 1436 1437 status_t status = device->InitCheck(); 1438 if (status == B_OK) 1439 status = devfs_publish_device(path, device); 1440 1441 if (status != B_OK) 1442 delete device; 1443 1444 return status; 1445 } 1446 1447 1448 extern "C" status_t 1449 legacy_driver_rescan(const char* driverName) 1450 { 1451 RecursiveLocker locker(sLock); 1452 1453 legacy_driver* driver = sDriverHash->Lookup(driverName); 1454 if (driver == NULL) 1455 return B_ENTRY_NOT_FOUND; 1456 1457 // Republish the driver's entries 1458 return republish_driver(driver); 1459 } 1460 1461 1462 extern "C" status_t 1463 legacy_driver_probe(const char* subPath) 1464 { 1465 TRACE(("legacy_driver_probe(type = %s)\n", subPath)); 1466 1467 char devicePath[64]; 1468 snprintf(devicePath, sizeof(devicePath), "drivers/dev%s%s", 1469 subPath[0] ? "/" : "", subPath); 1470 1471 if (!sWatching && gBootDevice > 0) { 1472 // We're probing the actual boot volume for the first time, 1473 // let's watch its driver directories for changes 1474 const directory_which whichPath[] = { 1475 B_USER_NONPACKAGED_ADDONS_DIRECTORY, 1476 B_USER_ADDONS_DIRECTORY, 1477 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, 1478 B_BEOS_ADDONS_DIRECTORY 1479 }; 1480 KPath path; 1481 1482 new(&sDirectoryWatcher) DirectoryWatcher; 1483 1484 bool disableUserAddOns = get_safemode_boolean( 1485 B_SAFEMODE_DISABLE_USER_ADD_ONS, false); 1486 1487 for (uint32 i = 0; i < sizeof(whichPath) / sizeof(whichPath[0]); i++) { 1488 if (i < 2 && disableUserAddOns) 1489 continue; 1490 1491 if (__find_directory(whichPath[i], gBootDevice, true, 1492 path.LockBuffer(), path.BufferSize()) == B_OK) { 1493 path.UnlockBuffer(); 1494 path.Append("kernel/drivers"); 1495 1496 start_watching(path.Path(), "dev"); 1497 start_watching(path.Path(), "bin"); 1498 } else 1499 path.UnlockBuffer(); 1500 } 1501 1502 sWatching = true; 1503 } 1504 1505 return probe_for_drivers(devicePath); 1506 } 1507 1508 1509 extern "C" status_t 1510 legacy_driver_init(void) 1511 { 1512 sDriverHash = new DriverTable(); 1513 if (sDriverHash == NULL || sDriverHash->Init(DRIVER_HASH_SIZE) != B_OK) 1514 return B_NO_MEMORY; 1515 1516 recursive_lock_init(&sLock, "legacy driver"); 1517 1518 new(&sDriverWatcher) DriverWatcher; 1519 new(&sDriverEvents) DriverEventList; 1520 1521 register_kernel_daemon(&handle_driver_events, NULL, 10); 1522 // once every second 1523 1524 add_debugger_command("legacy_driver", &dump_driver, 1525 "info about a legacy driver entry"); 1526 add_debugger_command("legacy_device", &dump_device, 1527 "info about a legacy device"); 1528 1529 return B_OK; 1530 } 1531