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