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 virtual status_t Control(void* cookie, int32 op, void* buffer, size_t length); 75 76 bool Republished() const { return fRepublished; } 77 void SetRepublished(bool republished) 78 { fRepublished = republished; } 79 80 void SetRemovedFromParent(bool removed) 81 { fRemovedFromParent = removed; } 82 83 private: 84 legacy_driver* fDriver; 85 const char* fPath; 86 device_hooks* fHooks; 87 bool fRepublished; 88 bool fRemovedFromParent; 89 }; 90 91 typedef DoublyLinkedList<LegacyDevice> DeviceList; 92 93 struct legacy_driver { 94 legacy_driver* next; 95 const char* path; 96 const char* name; 97 dev_t device; 98 ino_t node; 99 timespec last_modified; 100 image_id image; 101 uint32 devices_used; 102 bool binary_updated; 103 int32 priority; 104 DeviceList devices; 105 106 // driver image information 107 int32 api_version; 108 device_hooks* (*find_device)(const char *); 109 const char** (*publish_devices)(void); 110 status_t (*uninit_driver)(void); 111 status_t (*uninit_hardware)(void); 112 }; 113 114 115 enum driver_event_type { 116 kAddDriver, 117 kRemoveDriver, 118 kAddWatcher, 119 kRemoveWatcher 120 }; 121 122 struct driver_event : DoublyLinkedListLinkImpl<driver_event> { 123 driver_event(driver_event_type _type) : type(_type) {} 124 125 struct ref { 126 dev_t device; 127 ino_t node; 128 }; 129 130 driver_event_type type; 131 union { 132 char path[B_PATH_NAME_LENGTH]; 133 ref node; 134 }; 135 }; 136 137 typedef DoublyLinkedList<driver_event> DriverEventList; 138 139 140 struct driver_entry : DoublyLinkedListLinkImpl<driver_entry> { 141 char* path; 142 dev_t device; 143 ino_t node; 144 int32 busses; 145 }; 146 147 typedef DoublyLinkedList<driver_entry> DriverEntryList; 148 149 150 struct node_entry : DoublyLinkedListLinkImpl<node_entry> { 151 }; 152 153 typedef DoublyLinkedList<node_entry> NodeList; 154 155 156 struct directory_node_entry { 157 directory_node_entry* hash_link; 158 ino_t node; 159 }; 160 161 struct DirectoryNodeHashDefinition { 162 typedef ino_t* KeyType; 163 typedef directory_node_entry ValueType; 164 165 size_t HashKey(ino_t* key) const 166 { return _Hash(*key); } 167 size_t Hash(directory_node_entry* entry) const 168 { return _Hash(entry->node); } 169 bool Compare(ino_t* key, directory_node_entry* entry) const 170 { return *key == entry->node; } 171 directory_node_entry*& 172 GetLink(directory_node_entry* entry) const 173 { return entry->hash_link; } 174 175 uint32 _Hash(ino_t node) const 176 { return (uint32)(node >> 32) + (uint32)node; } 177 }; 178 179 typedef BOpenHashTable<DirectoryNodeHashDefinition> DirectoryNodeHash; 180 181 class DirectoryIterator { 182 public: 183 DirectoryIterator(const char *path, 184 const char *subPath = NULL, bool recursive = false); 185 ~DirectoryIterator(); 186 187 void SetTo(const char *path, const char *subPath = NULL, 188 bool recursive = false); 189 190 status_t GetNext(KPath &path, struct stat &stat); 191 const char* CurrentName() const { return fCurrentName; } 192 193 void Unset(); 194 void AddPath(const char *path, const char *subPath = NULL); 195 196 private: 197 Stack<KPath*> fPaths; 198 bool fRecursive; 199 DIR* fDirectory; 200 KPath* fBasePath; 201 const char* fCurrentName; 202 }; 203 204 205 class DirectoryWatcher : public NotificationListener { 206 public: 207 DirectoryWatcher(); 208 virtual ~DirectoryWatcher(); 209 210 virtual void EventOccurred(NotificationService& service, 211 const KMessage* event); 212 }; 213 214 class DriverWatcher : public NotificationListener { 215 public: 216 DriverWatcher(); 217 virtual ~DriverWatcher(); 218 219 virtual void EventOccurred(NotificationService& service, 220 const KMessage* event); 221 }; 222 223 224 struct DriverHash { 225 typedef const char* KeyType; 226 typedef legacy_driver ValueType; 227 228 size_t HashKey(KeyType key) const 229 { 230 return hash_hash_string(key); 231 } 232 233 size_t Hash(ValueType* driver) const 234 { 235 return HashKey(driver->name); 236 } 237 238 bool Compare(KeyType key, ValueType* driver) const 239 { 240 return strcmp(driver->name, key) == 0; 241 } 242 243 ValueType*& GetLink(ValueType* value) const 244 { 245 return value->next; 246 } 247 }; 248 249 typedef BOpenHashTable<DriverHash> DriverTable; 250 251 252 } // unnamed namespace 253 254 255 static status_t unload_driver(legacy_driver *driver); 256 static status_t load_driver(legacy_driver *driver); 257 258 259 static const directory_which kDriverPaths[] = { 260 B_USER_NONPACKAGED_ADDONS_DIRECTORY, 261 B_USER_ADDONS_DIRECTORY, 262 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, 263 B_SYSTEM_ADDONS_DIRECTORY 264 }; 265 266 static DriverWatcher sDriverWatcher; 267 static int32 sDriverEventsPending; 268 static DriverEventList sDriverEvents; 269 static mutex sDriverEventsLock = MUTEX_INITIALIZER("driver events"); 270 // inner lock, protects the sDriverEvents list only 271 static DirectoryWatcher sDirectoryWatcher; 272 static DirectoryNodeHash sDirectoryNodeHash; 273 static recursive_lock sLock; 274 static bool sWatching; 275 276 static DriverTable* sDriverHash; 277 278 279 // #pragma mark - driver private 280 281 282 /*! Collects all published devices of a driver, compares them to what the 283 driver would publish now, and then publishes/unpublishes the devices 284 as needed. 285 If the driver does not publish any devices anymore, it is unloaded. 286 */ 287 static status_t 288 republish_driver(legacy_driver* driver) 289 { 290 if (driver->image < 0) { 291 // The driver is not yet loaded - go through the normal load procedure 292 return load_driver(driver); 293 } 294 295 // mark all devices 296 DeviceList::Iterator iterator = driver->devices.GetIterator(); 297 while (LegacyDevice* device = iterator.Next()) { 298 device->SetRepublished(false); 299 } 300 301 // now ask the driver for it's currently published devices 302 const char** devicePaths = driver->publish_devices(); 303 304 int32 exported = 0; 305 for (; devicePaths != NULL && devicePaths[0]; devicePaths++) { 306 LegacyDevice* device; 307 308 iterator = driver->devices.GetIterator(); 309 while ((device = iterator.Next()) != NULL) { 310 if (!strncmp(device->Path(), devicePaths[0], B_PATH_NAME_LENGTH)) { 311 // mark device as republished 312 device->SetRepublished(true); 313 exported++; 314 break; 315 } 316 } 317 318 device_hooks* hooks = driver->find_device(devicePaths[0]); 319 if (hooks == NULL) 320 continue; 321 322 if (device != NULL) { 323 // update hooks 324 device->SetHooks(hooks); 325 continue; 326 } 327 328 // the device was not present before -> publish it now 329 TRACE(("devfs: publishing new device \"%s\"\n", devicePaths[0])); 330 device = new(std::nothrow) LegacyDevice(driver, devicePaths[0], hooks); 331 if (device != NULL && device->InitCheck() == B_OK 332 && devfs_publish_device(devicePaths[0], device) == B_OK) { 333 driver->devices.Add(device); 334 exported++; 335 } else 336 delete device; 337 } 338 339 // remove all devices that weren't republished 340 iterator = driver->devices.GetIterator(); 341 while (LegacyDevice* device = iterator.Next()) { 342 if (device->Republished()) 343 continue; 344 345 TRACE(("devfs: unpublishing no more present \"%s\"\n", device->Path())); 346 iterator.Remove(); 347 device->SetRemovedFromParent(true); 348 349 devfs_unpublish_device(device, true); 350 } 351 352 if (exported == 0 && driver->devices_used == 0 && gBootDevice >= 0) { 353 TRACE(("devfs: driver \"%s\" does not publish any more nodes and is " 354 "unloaded\n", driver->path)); 355 unload_driver(driver); 356 } 357 358 return B_OK; 359 } 360 361 362 static status_t 363 load_driver(legacy_driver* driver) 364 { 365 status_t (*init_hardware)(void); 366 status_t (*init_driver)(void); 367 status_t status; 368 369 driver->binary_updated = false; 370 371 // load the module 372 image_id image = driver->image; 373 if (image < 0) { 374 image = load_kernel_add_on(driver->path); 375 if (image < 0) 376 return image; 377 } 378 379 // For a valid device driver the following exports are required 380 381 int32* apiVersion; 382 if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, 383 (void**)&apiVersion) == B_OK) { 384 #if B_CUR_DRIVER_API_VERSION != 2 385 // just in case someone decides to bump up the api version 386 #error Add checks here for new vs old api version! 387 #endif 388 if (*apiVersion > B_CUR_DRIVER_API_VERSION) { 389 dprintf("devfs: \"%s\" api_version %" B_PRId32 " not handled\n", 390 driver->name, *apiVersion); 391 status = B_BAD_VALUE; 392 goto error1; 393 } 394 if (*apiVersion < 1) { 395 dprintf("devfs: \"%s\" api_version invalid\n", driver->name); 396 status = B_BAD_VALUE; 397 goto error1; 398 } 399 400 driver->api_version = *apiVersion; 401 } else 402 dprintf("devfs: \"%s\" api_version missing\n", driver->name); 403 404 if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, 405 (void**)&driver->publish_devices) != B_OK 406 || get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, 407 (void**)&driver->find_device) != B_OK) { 408 dprintf("devfs: \"%s\" mandatory driver symbol(s) missing!\n", 409 driver->name); 410 status = B_BAD_VALUE; 411 goto error1; 412 } 413 414 // Init the driver 415 416 if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT, 417 (void**)&init_hardware) == B_OK 418 && (status = init_hardware()) != B_OK) { 419 TRACE(("%s: init_hardware() failed: %s\n", driver->name, 420 strerror(status))); 421 status = ENXIO; 422 goto error1; 423 } 424 425 if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT, 426 (void**)&init_driver) == B_OK 427 && (status = init_driver()) != B_OK) { 428 TRACE(("%s: init_driver() failed: %s\n", driver->name, 429 strerror(status))); 430 status = ENXIO; 431 goto error2; 432 } 433 434 // resolve and cache those for the driver unload code 435 if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT, 436 (void**)&driver->uninit_driver) != B_OK) 437 driver->uninit_driver = NULL; 438 if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT, 439 (void**)&driver->uninit_hardware) != B_OK) 440 driver->uninit_hardware = NULL; 441 442 // The driver has successfully been initialized, now we can 443 // finally publish its device entries 444 445 driver->image = image; 446 return republish_driver(driver); 447 448 error2: 449 if (driver->uninit_hardware) 450 driver->uninit_hardware(); 451 452 error1: 453 if (driver->image < 0) { 454 unload_kernel_add_on(image); 455 driver->image = status; 456 } 457 458 return status; 459 } 460 461 462 static status_t 463 unload_driver(legacy_driver* driver) 464 { 465 if (driver->image < 0) { 466 // driver is not currently loaded 467 return B_NO_INIT; 468 } 469 470 if (driver->uninit_driver) 471 driver->uninit_driver(); 472 473 if (driver->uninit_hardware) 474 driver->uninit_hardware(); 475 476 unload_kernel_add_on(driver->image); 477 driver->image = -1; 478 driver->binary_updated = false; 479 driver->find_device = NULL; 480 driver->publish_devices = NULL; 481 driver->uninit_driver = NULL; 482 driver->uninit_hardware = NULL; 483 484 return B_OK; 485 } 486 487 488 /*! Unpublishes all devices belonging to the \a driver. */ 489 static void 490 unpublish_driver(legacy_driver* driver) 491 { 492 while (LegacyDevice* device = driver->devices.RemoveHead()) { 493 device->SetRemovedFromParent(true); 494 devfs_unpublish_device(device, true); 495 } 496 } 497 498 499 static void 500 change_driver_watcher(dev_t device, ino_t node, bool add) 501 { 502 if (device == -1) 503 return; 504 505 driver_event* event = new (std::nothrow) driver_event( 506 add ? kAddWatcher : kRemoveWatcher); 507 if (event == NULL) 508 return; 509 510 event->node.device = device; 511 event->node.node = node; 512 513 MutexLocker _(sDriverEventsLock); 514 sDriverEvents.Add(event); 515 516 atomic_add(&sDriverEventsPending, 1); 517 } 518 519 520 static int32 521 get_priority(const char* path) 522 { 523 // TODO: would it be better to initialize a static structure here 524 // using find_directory()? 525 const directory_which whichPath[] = { 526 B_SYSTEM_DIRECTORY, 527 B_SYSTEM_NONPACKAGED_DIRECTORY, 528 B_USER_DIRECTORY 529 }; 530 KPath pathBuffer; 531 532 for (uint32 index = 0; index < B_COUNT_OF(whichPath); index++) { 533 if (__find_directory(whichPath[index], gBootDevice, false, 534 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { 535 pathBuffer.UnlockBuffer(); 536 if (strncmp(pathBuffer.Path(), path, pathBuffer.Length()) == 0) 537 return index; 538 } else 539 pathBuffer.UnlockBuffer(); 540 } 541 542 return -1; 543 } 544 545 546 static const char* 547 get_leaf(const char* path) 548 { 549 const char* name = strrchr(path, '/'); 550 if (name == NULL) 551 return path; 552 553 return name + 1; 554 } 555 556 557 static legacy_driver* 558 find_driver(dev_t device, ino_t node) 559 { 560 DriverTable::Iterator iterator(sDriverHash); 561 while (iterator.HasNext()) { 562 legacy_driver* driver = iterator.Next(); 563 if (driver->device == device && driver->node == node) 564 return driver; 565 } 566 567 return NULL; 568 } 569 570 571 static status_t 572 add_driver(const char* path, image_id image) 573 { 574 // Check if we already know this driver 575 576 struct stat stat; 577 if (image >= 0) { 578 // The image ID should be a small number and hopefully the boot FS 579 // doesn't use small negative values -- if it is inode based, we should 580 // be relatively safe. 581 stat.st_dev = -1; 582 stat.st_ino = -1; 583 } else { 584 if (::stat(path, &stat) != 0) 585 return errno; 586 } 587 588 int32 priority = get_priority(path); 589 590 RecursiveLocker _(sLock); 591 592 legacy_driver* driver = sDriverHash->Lookup(get_leaf(path)); 593 if (driver != NULL) { 594 // we know this driver 595 if (strcmp(driver->path, path) != 0 && priority >= driver->priority) { 596 // TODO: do properly, but for now we just update the path if it 597 // isn't the same anymore so rescanning of drivers will work in 598 // case this driver was loaded so early that it has a boot module 599 // path and not a proper driver path 600 free((char*)driver->path); 601 driver->path = strdup(path); 602 driver->name = get_leaf(driver->path); 603 driver->binary_updated = true; 604 } 605 606 // TODO: check if this driver is a different one and has precedence 607 // (ie. common supersedes system). 608 //dprintf("new driver has priority %ld, old %ld\n", priority, driver->priority); 609 if (priority >= driver->priority) { 610 driver->binary_updated = true; 611 return B_OK; 612 } 613 614 // TODO: test for changes here and/or via node monitoring and reload 615 // the driver if necessary 616 if (driver->image < B_OK) 617 return driver->image; 618 619 return B_OK; 620 } 621 622 // we don't know this driver, create a new entry for it 623 624 driver = (legacy_driver*)malloc(sizeof(legacy_driver)); 625 if (driver == NULL) 626 return B_NO_MEMORY; 627 628 driver->path = strdup(path); 629 if (driver->path == NULL) { 630 free(driver); 631 return B_NO_MEMORY; 632 } 633 634 driver->name = get_leaf(driver->path); 635 driver->device = stat.st_dev; 636 driver->node = stat.st_ino; 637 driver->image = image; 638 driver->last_modified = stat.st_mtim; 639 driver->devices_used = 0; 640 driver->binary_updated = false; 641 driver->priority = priority; 642 643 driver->api_version = 1; 644 driver->find_device = NULL; 645 driver->publish_devices = NULL; 646 driver->uninit_driver = NULL; 647 driver->uninit_hardware = NULL; 648 new(&driver->devices) DeviceList; 649 650 sDriverHash->Insert(driver); 651 if (stat.st_dev > 0) 652 change_driver_watcher(stat.st_dev, stat.st_ino, true); 653 654 // Even if loading the driver fails - its entry will stay with us 655 // so that we don't have to go through it again 656 return load_driver(driver); 657 } 658 659 660 /*! This is no longer part of the public kernel API, so we just export the 661 symbol 662 */ 663 extern "C" status_t load_driver_symbols(const char* driverName); 664 status_t 665 load_driver_symbols(const char* driverName) 666 { 667 // This is done globally for the whole kernel via the settings file. 668 // We don't have to do anything here. 669 670 return B_OK; 671 } 672 673 674 static status_t 675 reload_driver(legacy_driver* driver) 676 { 677 dprintf("devfs: reload driver \"%s\" (%" B_PRIdDEV ", %" B_PRIdINO ")\n", 678 driver->name, driver->device, driver->node); 679 680 unload_driver(driver); 681 682 struct stat stat; 683 if (::stat(driver->path, &stat) == 0 684 && (stat.st_dev != driver->device || stat.st_ino != driver->node)) { 685 // The driver file has been changed, so we need to update its listener 686 change_driver_watcher(driver->device, driver->node, false); 687 688 driver->device = stat.st_dev; 689 driver->node = stat.st_ino; 690 691 change_driver_watcher(driver->device, driver->node, true); 692 } 693 694 status_t status = load_driver(driver); 695 if (status != B_OK) 696 unpublish_driver(driver); 697 698 return status; 699 } 700 701 702 static void 703 handle_driver_events(void* /*_fs*/, int /*iteration*/) 704 { 705 if (atomic_and(&sDriverEventsPending, 0) == 0) 706 return; 707 708 // something happened, let's see what it was 709 710 while (true) { 711 MutexLocker eventLocker(sDriverEventsLock); 712 713 driver_event* event = sDriverEvents.RemoveHead(); 714 if (event == NULL) 715 break; 716 717 eventLocker.Unlock(); 718 TRACE(("driver event %p, type %d\n", event, event->type)); 719 720 switch (event->type) { 721 case kAddDriver: 722 { 723 // Add new drivers 724 RecursiveLocker locker(sLock); 725 TRACE((" add driver %p\n", event->path)); 726 727 legacy_driver* driver = sDriverHash->Lookup( 728 get_leaf(event->path)); 729 if (driver == NULL) 730 legacy_driver_add(event->path); 731 else if (get_priority(event->path) >= driver->priority) 732 driver->binary_updated = true; 733 break; 734 } 735 736 case kRemoveDriver: 737 { 738 // Mark removed drivers as updated 739 RecursiveLocker locker(sLock); 740 TRACE((" remove driver %p\n", event->path)); 741 742 legacy_driver* driver = sDriverHash->Lookup( 743 get_leaf(event->path)); 744 if (driver != NULL 745 && get_priority(event->path) >= driver->priority) 746 driver->binary_updated = true; 747 break; 748 } 749 750 case kAddWatcher: 751 TRACE((" add watcher %" B_PRId32 ":%" B_PRIdINO "\n", event->node.device, 752 event->node.node)); 753 add_node_listener(event->node.device, event->node.node, 754 B_WATCH_STAT | B_WATCH_NAME, sDriverWatcher); 755 break; 756 757 case kRemoveWatcher: 758 TRACE((" remove watcher %" B_PRId32 ":%" B_PRIdINO "\n", event->node.device, 759 event->node.node)); 760 remove_node_listener(event->node.device, event->node.node, 761 sDriverWatcher); 762 break; 763 } 764 765 delete event; 766 } 767 768 // Reload updated drivers 769 770 RecursiveLocker locker(sLock); 771 772 DriverTable::Iterator iterator(sDriverHash); 773 while (iterator.HasNext()) { 774 legacy_driver* driver = iterator.Next(); 775 776 if (!driver->binary_updated || driver->devices_used != 0) 777 continue; 778 779 // try to reload the driver 780 reload_driver(driver); 781 } 782 783 locker.Unlock(); 784 } 785 786 787 // #pragma mark - DriverWatcher 788 789 790 DriverWatcher::DriverWatcher() 791 { 792 } 793 794 795 DriverWatcher::~DriverWatcher() 796 { 797 } 798 799 800 void 801 DriverWatcher::EventOccurred(NotificationService& service, 802 const KMessage* event) 803 { 804 int32 opcode = event->GetInt32("opcode", -1); 805 if (opcode != B_STAT_CHANGED 806 || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0) 807 return; 808 809 RecursiveLocker locker(sLock); 810 811 legacy_driver* driver = find_driver(event->GetInt32("device", -1), 812 event->GetInt64("node", 0)); 813 if (driver == NULL) 814 return; 815 816 driver->binary_updated = true; 817 818 if (driver->devices_used == 0) { 819 // trigger a reload of the driver 820 atomic_add(&sDriverEventsPending, 1); 821 } else { 822 // driver is in use right now 823 dprintf("devfs: changed driver \"%s\" is still in use\n", driver->name); 824 } 825 } 826 827 828 static void 829 dump_driver(legacy_driver* driver) 830 { 831 kprintf("DEVFS DRIVER: %p\n", driver); 832 kprintf(" name: %s\n", driver->name); 833 kprintf(" path: %s\n", driver->path); 834 kprintf(" image: %" B_PRId32 "\n", driver->image); 835 kprintf(" device: %" B_PRIdDEV "\n", driver->device); 836 kprintf(" node: %" B_PRIdINO "\n", driver->node); 837 kprintf(" last modified: %" B_PRIdTIME ".%ld\n", driver->last_modified.tv_sec, 838 driver->last_modified.tv_nsec); 839 kprintf(" devs used: %" B_PRIu32 "\n", driver->devices_used); 840 kprintf(" devs published: %" B_PRId32 "\n", driver->devices.Count()); 841 kprintf(" binary updated: %d\n", driver->binary_updated); 842 kprintf(" priority: %" B_PRId32 "\n", driver->priority); 843 kprintf(" api version: %" B_PRId32 "\n", driver->api_version); 844 kprintf(" hooks: find_device %p, publish_devices %p\n" 845 " uninit_driver %p, uninit_hardware %p\n", 846 driver->find_device, driver->publish_devices, driver->uninit_driver, 847 driver->uninit_hardware); 848 } 849 850 851 static int 852 dump_device(int argc, char** argv) 853 { 854 if (argc < 2 || !strcmp(argv[1], "--help")) { 855 kprintf("usage: %s [device]\n", argv[0]); 856 return 0; 857 } 858 859 LegacyDevice* device = (LegacyDevice*)parse_expression(argv[1]); 860 861 kprintf("LEGACY DEVICE: %p\n", device); 862 kprintf(" path: %s\n", device->Path()); 863 kprintf(" hooks: %p\n", device->Hooks()); 864 device_hooks* hooks = device->Hooks(); 865 kprintf(" close() %p\n", hooks->close); 866 kprintf(" free() %p\n", hooks->free); 867 kprintf(" control() %p\n", hooks->control); 868 kprintf(" read() %p\n", hooks->read); 869 kprintf(" write() %p\n", hooks->write); 870 kprintf(" select() %p\n", hooks->select); 871 kprintf(" deselect() %p\n", hooks->deselect); 872 dump_driver(device->Driver()); 873 874 return 0; 875 } 876 877 878 static int 879 dump_driver(int argc, char** argv) 880 { 881 if (argc < 2) { 882 // print list of all drivers 883 kprintf("address image used publ. pri name\n"); 884 DriverTable::Iterator iterator(sDriverHash); 885 while (iterator.HasNext()) { 886 legacy_driver* driver = iterator.Next(); 887 888 kprintf("%p %5" B_PRId32 " %3" B_PRIu32 " %5" B_PRId32 " %c " 889 "%3" B_PRId32 " %s\n", driver, 890 driver->image < 0 ? -1 : driver->image, 891 driver->devices_used, driver->devices.Count(), 892 driver->binary_updated ? 'U' : ' ', driver->priority, 893 driver->name); 894 } 895 896 return 0; 897 } 898 899 if (!strcmp(argv[1], "--help")) { 900 kprintf("usage: %s [name]\n", argv[0]); 901 return 0; 902 } 903 904 legacy_driver* driver = sDriverHash->Lookup(argv[1]); 905 if (driver == NULL) { 906 kprintf("Driver named \"%s\" not found.\n", argv[1]); 907 return 0; 908 } 909 910 dump_driver(driver); 911 return 0; 912 } 913 914 915 // #pragma mark - 916 917 918 DirectoryIterator::DirectoryIterator(const char* path, const char* subPath, 919 bool recursive) 920 : 921 fDirectory(NULL), 922 fBasePath(NULL), 923 fCurrentName(NULL) 924 { 925 SetTo(path, subPath, recursive); 926 } 927 928 929 DirectoryIterator::~DirectoryIterator() 930 { 931 Unset(); 932 } 933 934 935 void 936 DirectoryIterator::SetTo(const char* path, const char* subPath, bool recursive) 937 { 938 Unset(); 939 fRecursive = recursive; 940 941 const bool disableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS, false); 942 943 if (path == NULL) { 944 // add default paths in reverse order as AddPath() will add on a stack 945 KPath pathBuffer; 946 for (int32 i = B_COUNT_OF(kDriverPaths) - 1; i >= 0; i--) { 947 if (i < 3 && disableUserAddOns) 948 continue; 949 950 if (__find_directory(kDriverPaths[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 = new(std::nothrow) driver_entry; 1134 if (entry == NULL) 1135 return NULL; 1136 1137 entry->path = strdup(path); 1138 if (entry->path == NULL) { 1139 delete 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 delete 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 SetHooks(hooks); 1254 } 1255 1256 fDeviceData = this; 1257 fPath = strdup(path); 1258 1259 } 1260 1261 1262 LegacyDevice::~LegacyDevice() 1263 { 1264 free(fDeviceModule); 1265 free((char*)fPath); 1266 } 1267 1268 1269 status_t 1270 LegacyDevice::InitCheck() const 1271 { 1272 return fDeviceModule != NULL && fPath != NULL ? B_OK : B_NO_MEMORY; 1273 } 1274 1275 1276 status_t 1277 LegacyDevice::InitDevice() 1278 { 1279 RecursiveLocker _(sLock); 1280 1281 if (fInitialized++ > 0) 1282 return B_OK; 1283 1284 if (fDriver != NULL && fDriver->devices_used == 0 1285 && (fDriver->image < 0 || fDriver->binary_updated)) { 1286 status_t status = reload_driver(fDriver); 1287 if (status < B_OK) 1288 return status; 1289 } 1290 1291 if (fDriver != NULL) 1292 fDriver->devices_used++; 1293 1294 return B_OK; 1295 } 1296 1297 1298 void 1299 LegacyDevice::UninitDevice() 1300 { 1301 RecursiveLocker _(sLock); 1302 1303 if (fInitialized-- > 1) 1304 return; 1305 1306 if (fDriver != NULL) { 1307 if (--fDriver->devices_used == 0 && fDriver->devices.IsEmpty()) 1308 unload_driver(fDriver); 1309 fDriver = NULL; 1310 } 1311 } 1312 1313 1314 void 1315 LegacyDevice::Removed() 1316 { 1317 RecursiveLocker _(sLock); 1318 1319 if (!fRemovedFromParent && fDriver != NULL) 1320 fDriver->devices.Remove(this); 1321 1322 delete this; 1323 } 1324 1325 1326 status_t 1327 LegacyDevice::Control(void* _cookie, int32 op, void* buffer, size_t length) 1328 { 1329 switch (op) { 1330 case B_GET_DRIVER_FOR_DEVICE: 1331 if (length != 0 && length <= strlen(fDriver->path)) 1332 return ERANGE; 1333 return user_strlcpy(static_cast<char*>(buffer), fDriver->path, length); 1334 default: 1335 return AbstractModuleDevice::Control(_cookie, op, buffer, length); 1336 } 1337 } 1338 1339 1340 void 1341 LegacyDevice::SetHooks(device_hooks* hooks) 1342 { 1343 // TODO: setup compatibility layer! 1344 fHooks = hooks; 1345 1346 fDeviceModule->close = hooks->close; 1347 fDeviceModule->free = hooks->free; 1348 fDeviceModule->control = hooks->control; 1349 fDeviceModule->read = hooks->read; 1350 fDeviceModule->write = hooks->write; 1351 1352 if (fDriver == NULL || fDriver->api_version >= 2) { 1353 // According to Be newsletter, vol II, issue 36, 1354 // version 2 added readv/writev, which we don't support, but also 1355 // select/deselect. 1356 if (hooks->select != NULL) { 1357 // Note we set the module's select to a non-null value to indicate 1358 // that we have select. HasSelect() will therefore return the 1359 // correct answer. As Select() is virtual our compatibility 1360 // version below is going to be called though, that redirects to 1361 // the proper select hook, so it is ok to set it to an invalid 1362 // address here. 1363 fDeviceModule->select = (status_t (*)(void*, uint8, selectsync*))~0; 1364 } 1365 1366 fDeviceModule->deselect = hooks->deselect; 1367 } 1368 } 1369 1370 1371 status_t 1372 LegacyDevice::Open(const char* path, int openMode, void** _cookie) 1373 { 1374 return Hooks()->open(path, openMode, _cookie); 1375 } 1376 1377 1378 status_t 1379 LegacyDevice::Select(void* cookie, uint8 event, selectsync* sync) 1380 { 1381 return Hooks()->select(cookie, event, 0, sync); 1382 } 1383 1384 1385 // #pragma mark - kernel private API 1386 1387 1388 extern "C" void 1389 legacy_driver_add_preloaded(kernel_args* args) 1390 { 1391 // NOTE: This function does not exit in case of error, since it 1392 // needs to unload the images then. Also the return code of 1393 // the path operations is kept separate from the add_driver() 1394 // success, so that even if add_driver() fails for one driver, it 1395 // is still tried for the other drivers. 1396 // NOTE: The initialization success of the path objects is implicitely 1397 // checked by the immediately following functions. 1398 KPath basePath; 1399 status_t status = __find_directory(B_SYSTEM_ADDONS_DIRECTORY, 1400 gBootDevice, false, basePath.LockBuffer(), basePath.BufferSize()); 1401 if (status != B_OK) { 1402 dprintf("legacy_driver_add_preloaded: find_directory() failed: " 1403 "%s\n", strerror(status)); 1404 } 1405 basePath.UnlockBuffer(); 1406 if (status == B_OK) 1407 status = basePath.Append("kernel"); 1408 if (status != B_OK) { 1409 dprintf("legacy_driver_add_preloaded: constructing base driver " 1410 "path failed: %s\n", strerror(status)); 1411 return; 1412 } 1413 1414 struct preloaded_image* image; 1415 for (image = args->preloaded_images; image != NULL; image = image->next) { 1416 if (image->is_module || image->id < 0) 1417 continue; 1418 1419 KPath imagePath(basePath); 1420 status = imagePath.Append(image->name); 1421 1422 // try to add the driver 1423 TRACE(("legacy_driver_add_preloaded: adding driver %s\n", 1424 imagePath.Path())); 1425 1426 if (status == B_OK) 1427 status = add_driver(imagePath.Path(), image->id); 1428 if (status != B_OK) { 1429 dprintf("legacy_driver_add_preloaded: Failed to add \"%s\": %s\n", 1430 (char*)image->name, strerror(status)); 1431 unload_kernel_add_on(image->id); 1432 } 1433 } 1434 } 1435 1436 1437 extern "C" status_t 1438 legacy_driver_add(const char* path) 1439 { 1440 return add_driver(path, -1); 1441 } 1442 1443 1444 extern "C" status_t 1445 legacy_driver_publish(const char* path, device_hooks* hooks) 1446 { 1447 // we don't have a driver, just publish the hooks 1448 LegacyDevice* device = new(std::nothrow) LegacyDevice(NULL, path, hooks); 1449 if (device == NULL) 1450 return B_NO_MEMORY; 1451 1452 status_t status = device->InitCheck(); 1453 if (status == B_OK) 1454 status = devfs_publish_device(path, device); 1455 1456 if (status != B_OK) 1457 delete device; 1458 1459 return status; 1460 } 1461 1462 1463 extern "C" status_t 1464 legacy_driver_rescan(const char* driverName) 1465 { 1466 RecursiveLocker locker(sLock); 1467 1468 legacy_driver* driver = sDriverHash->Lookup(driverName); 1469 if (driver == NULL) 1470 return B_ENTRY_NOT_FOUND; 1471 1472 // Republish the driver's entries 1473 return republish_driver(driver); 1474 } 1475 1476 1477 extern "C" status_t 1478 legacy_driver_probe(const char* subPath) 1479 { 1480 TRACE(("legacy_driver_probe(type = %s)\n", subPath)); 1481 1482 char devicePath[64]; 1483 snprintf(devicePath, sizeof(devicePath), "drivers/dev%s%s", 1484 subPath[0] ? "/" : "", subPath); 1485 1486 if (!sWatching && gBootDevice > 0) { 1487 // We're probing the actual boot volume for the first time, 1488 // let's watch its driver directories for changes 1489 KPath path; 1490 1491 new(&sDirectoryWatcher) DirectoryWatcher; 1492 1493 bool disableUserAddOns = get_safemode_boolean( 1494 B_SAFEMODE_DISABLE_USER_ADD_ONS, false); 1495 1496 for (uint32 i = 0; i < sizeof(kDriverPaths) / sizeof(kDriverPaths[0]); i++) { 1497 if (i < 3 && disableUserAddOns) 1498 continue; 1499 1500 if (__find_directory(kDriverPaths[i], gBootDevice, true, 1501 path.LockBuffer(), path.BufferSize()) == B_OK) { 1502 path.UnlockBuffer(); 1503 path.Append("kernel/drivers"); 1504 1505 start_watching(path.Path(), "bin"); 1506 } else 1507 path.UnlockBuffer(); 1508 } 1509 1510 sWatching = true; 1511 } 1512 1513 return probe_for_drivers(devicePath); 1514 } 1515 1516 1517 extern "C" status_t 1518 legacy_driver_init(void) 1519 { 1520 sDriverHash = new(std::nothrow) DriverTable(); 1521 if (sDriverHash == NULL || sDriverHash->Init(DRIVER_HASH_SIZE) != B_OK) 1522 return B_NO_MEMORY; 1523 1524 recursive_lock_init(&sLock, "legacy driver"); 1525 1526 new(&sDriverWatcher) DriverWatcher; 1527 new(&sDriverEvents) DriverEventList; 1528 1529 register_kernel_daemon(&handle_driver_events, NULL, 10); 1530 // once every second 1531 1532 add_debugger_command("legacy_driver", &dump_driver, 1533 "info about a legacy driver entry"); 1534 add_debugger_command("legacy_device", &dump_device, 1535 "info about a legacy device"); 1536 1537 return B_OK; 1538 } 1539