1165619Sglebius/* 2165619Sglebius * Copyright 2002-2011, Axel D��rfler, axeld@pinc-software.de. 3165619Sglebius * Distributed under the terms of the MIT License. 4165619Sglebius */ 5165619Sglebius 6165619Sglebius 7165619Sglebius#include "legacy_drivers.h" 8165619Sglebius 9165619Sglebius#include <dirent.h> 10165619Sglebius#include <errno.h> 11165619Sglebius#include <new> 12165619Sglebius#include <stdio.h> 13165619Sglebius 14165619Sglebius#include <FindDirectory.h> 15165619Sglebius#include <image.h> 16165619Sglebius#include <NodeMonitor.h> 17165619Sglebius 18165619Sglebius#include <boot_device.h> 19165619Sglebius#include <boot/kernel_args.h> 20165619Sglebius#include <elf.h> 21165619Sglebius#include <find_directory_private.h> 22165619Sglebius#include <fs/devfs.h> 23165619Sglebius#include <fs/KPath.h> 24165619Sglebius#include <fs/node_monitor.h> 25165619Sglebius#include <Notifications.h> 26165619Sglebius#include <safemode.h> 27165619Sglebius#include <util/DoublyLinkedList.h> 28165619Sglebius#include <util/OpenHashTable.h> 29165619Sglebius#include <util/Stack.h> 30165619Sglebius#include <vfs.h> 31165619Sglebius 32165619Sglebius#include "AbstractModuleDevice.h" 33165619Sglebius#include "devfs_private.h" 34165619Sglebius 35165619Sglebius 36165619Sglebius//#define TRACE_LEGACY_DRIVERS 37165619Sglebius#ifdef TRACE_LEGACY_DRIVERS 38165619Sglebius# define TRACE(x) dprintf x 39165619Sglebius#else 40165619Sglebius# define TRACE(x) 41165619Sglebius#endif 42165619Sglebius 43165619Sglebius#define DRIVER_HASH_SIZE 16 44165619Sglebius 45165619Sglebius 46165619Sglebiusnamespace { 47165619Sglebius 48165619Sglebiusstruct legacy_driver; 49227293Sed 50165619Sglebiusclass LegacyDevice : public AbstractModuleDevice, 51165619Sglebius public DoublyLinkedListLinkImpl<LegacyDevice> { 52165619Sglebiuspublic: 53165619Sglebius LegacyDevice(legacy_driver* driver, 54165619Sglebius const char* path, device_hooks* hooks); 55165619Sglebius virtual ~LegacyDevice(); 56165619Sglebius 57165619Sglebius status_t InitCheck() const; 58165619Sglebius 59165619Sglebius virtual status_t InitDevice(); 60165619Sglebius virtual void UninitDevice(); 61165619Sglebius 62165619Sglebius virtual void Removed(); 63165619Sglebius 64165619Sglebius void SetHooks(device_hooks* hooks); 65165619Sglebius 66165619Sglebius legacy_driver* Driver() const { return fDriver; } 67165619Sglebius const char* Path() const { return fPath; } 68165619Sglebius device_hooks* Hooks() const { return fHooks; } 69165619Sglebius 70165619Sglebius virtual status_t Open(const char* path, int openMode, 71165619Sglebius void** _cookie); 72165619Sglebius virtual status_t Select(void* cookie, uint8 event, selectsync* sync); 73165619Sglebius 74165619Sglebius virtual status_t Control(void* cookie, int32 op, void* buffer, size_t length); 75165619Sglebius 76165619Sglebius bool Republished() const { return fRepublished; } 77165619Sglebius void SetRepublished(bool republished) 78165619Sglebius { fRepublished = republished; } 79165619Sglebius 80165619Sglebius void SetRemovedFromParent(bool removed) 81165619Sglebius { fRemovedFromParent = removed; } 82165619Sglebius 83165619Sglebiusprivate: 84165619Sglebius legacy_driver* fDriver; 85165619Sglebius const char* fPath; 86165619Sglebius device_hooks* fHooks; 87165619Sglebius bool fRepublished; 88165619Sglebius bool fRemovedFromParent; 89165619Sglebius}; 90165619Sglebius 91165619Sglebiustypedef DoublyLinkedList<LegacyDevice> DeviceList; 92165619Sglebius 93165619Sglebiusstruct legacy_driver { 94165619Sglebius legacy_driver* next; 95165619Sglebius const char* path; 96165619Sglebius const char* name; 97165619Sglebius dev_t device; 98165619Sglebius ino_t node; 99165619Sglebius timespec last_modified; 100165619Sglebius image_id image; 101165619Sglebius uint32 devices_used; 102165619Sglebius bool binary_updated; 103165619Sglebius int32 priority; 104165619Sglebius DeviceList devices; 105165619Sglebius 106165619Sglebius // driver image information 107165619Sglebius int32 api_version; 108165619Sglebius device_hooks* (*find_device)(const char *); 109165619Sglebius const char** (*publish_devices)(void); 110165619Sglebius status_t (*uninit_driver)(void); 111165619Sglebius status_t (*uninit_hardware)(void); 112165619Sglebius}; 113165619Sglebius 114165619Sglebius 115165619Sglebiusenum driver_event_type { 116165619Sglebius kAddDriver, 117165619Sglebius kRemoveDriver, 118165619Sglebius kAddWatcher, 119165619Sglebius kRemoveWatcher 120165619Sglebius}; 121165619Sglebius 122165619Sglebiusstruct driver_event : DoublyLinkedListLinkImpl<driver_event> { 123165619Sglebius driver_event(driver_event_type _type) : type(_type) {} 124165619Sglebius 125165619Sglebius struct ref { 126165619Sglebius dev_t device; 127165619Sglebius ino_t node; 128165619Sglebius }; 129165619Sglebius 130165619Sglebius driver_event_type type; 131165619Sglebius union { 132165619Sglebius char path[B_PATH_NAME_LENGTH]; 133165619Sglebius ref node; 134165619Sglebius }; 135165619Sglebius}; 136165619Sglebius 137165619Sglebiustypedef DoublyLinkedList<driver_event> DriverEventList; 138165619Sglebius 139165619Sglebius 140165619Sglebiusstruct driver_entry : DoublyLinkedListLinkImpl<driver_entry> { 141165619Sglebius char* path; 142165619Sglebius dev_t device; 143165619Sglebius ino_t node; 144165619Sglebius int32 busses; 145165619Sglebius}; 146165619Sglebius 147165619Sglebiustypedef DoublyLinkedList<driver_entry> DriverEntryList; 148165619Sglebius 149165619Sglebius 150165619Sglebiusstruct node_entry : DoublyLinkedListLinkImpl<node_entry> { 151165619Sglebius}; 152165619Sglebius 153165619Sglebiustypedef DoublyLinkedList<node_entry> NodeList; 154165619Sglebius 155165619Sglebius 156165619Sglebiusstruct directory_node_entry { 157165619Sglebius directory_node_entry* hash_link; 158165619Sglebius ino_t node; 159165619Sglebius}; 160165619Sglebius 161165619Sglebiusstruct DirectoryNodeHashDefinition { 162165619Sglebius typedef ino_t* KeyType; 163165619Sglebius typedef directory_node_entry ValueType; 164165619Sglebius 165165619Sglebius size_t HashKey(ino_t* key) const 166165619Sglebius { return _Hash(*key); } 167165619Sglebius size_t Hash(directory_node_entry* entry) const 168165619Sglebius { return _Hash(entry->node); } 169165619Sglebius bool Compare(ino_t* key, directory_node_entry* entry) const 170165619Sglebius { return *key == entry->node; } 171165619Sglebius directory_node_entry*& 172165619Sglebius GetLink(directory_node_entry* entry) const 173165619Sglebius { return entry->hash_link; } 174165619Sglebius 175165619Sglebius uint32 _Hash(ino_t node) const 176165619Sglebius { return (uint32)(node >> 32) + (uint32)node; } 177165619Sglebius}; 178165619Sglebius 179165619Sglebiustypedef BOpenHashTable<DirectoryNodeHashDefinition> DirectoryNodeHash; 180165619Sglebius 181165619Sglebiusclass DirectoryIterator { 182165619Sglebiuspublic: 183165619Sglebius DirectoryIterator(const char *path, 184165619Sglebius const char *subPath = NULL, bool recursive = false); 185165619Sglebius ~DirectoryIterator(); 186165619Sglebius 187165619Sglebius void SetTo(const char *path, const char *subPath = NULL, 188165619Sglebius bool recursive = false); 189165619Sglebius 190165619Sglebius status_t GetNext(KPath &path, struct stat &stat); 191165619Sglebius const char* CurrentName() const { return fCurrentName; } 192165619Sglebius 193165619Sglebius void Unset(); 194165619Sglebius void AddPath(const char *path, const char *subPath = NULL); 195165619Sglebius 196165619Sglebiusprivate: 197165619Sglebius Stack<KPath*> fPaths; 198165619Sglebius bool fRecursive; 199165619Sglebius DIR* fDirectory; 200165619Sglebius KPath* fBasePath; 201165619Sglebius const char* fCurrentName; 202165619Sglebius}; 203165619Sglebius 204165619Sglebius 205165619Sglebiusclass DirectoryWatcher : public NotificationListener { 206165619Sglebiuspublic: 207165619Sglebius DirectoryWatcher(); 208165619Sglebius virtual ~DirectoryWatcher(); 209165619Sglebius 210165619Sglebius virtual void EventOccurred(NotificationService& service, 211165619Sglebius const KMessage* event); 212165619Sglebius}; 213165619Sglebius 214165619Sglebiusclass DriverWatcher : public NotificationListener { 215165619Sglebiuspublic: 216165619Sglebius DriverWatcher(); 217165619Sglebius virtual ~DriverWatcher(); 218165619Sglebius 219165619Sglebius virtual void EventOccurred(NotificationService& service, 220165619Sglebius const KMessage* event); 221165619Sglebius}; 222165619Sglebius 223165619Sglebius 224165619Sglebiusstruct DriverHash { 225165619Sglebius typedef const char* KeyType; 226165619Sglebius typedef legacy_driver ValueType; 227165619Sglebius 228165619Sglebius size_t HashKey(KeyType key) const 229165619Sglebius { 230165619Sglebius return hash_hash_string(key); 231165619Sglebius } 232165619Sglebius 233165619Sglebius size_t Hash(ValueType* driver) const 234165619Sglebius { 235165619Sglebius return HashKey(driver->name); 236165619Sglebius } 237165619Sglebius 238166019Sglebius bool Compare(KeyType key, ValueType* driver) const 239165619Sglebius { 240165619Sglebius return strcmp(driver->name, key) == 0; 241165619Sglebius } 242165619Sglebius 243165619Sglebius ValueType*& GetLink(ValueType* value) const 244165619Sglebius { 245165619Sglebius return value->next; 246165619Sglebius } 247165619Sglebius}; 248165619Sglebius 249165619Sglebiustypedef BOpenHashTable<DriverHash> DriverTable; 250165619Sglebius 251165619Sglebius 252165619Sglebius} // unnamed namespace 253165619Sglebius 254165619Sglebius 255165619Sglebiusstatic status_t unload_driver(legacy_driver *driver); 256165619Sglebiusstatic status_t load_driver(legacy_driver *driver); 257165619Sglebius 258165619Sglebius 259165619Sglebiusstatic const directory_which kDriverPaths[] = { 260165619Sglebius B_USER_NONPACKAGED_ADDONS_DIRECTORY, 261165619Sglebius B_USER_ADDONS_DIRECTORY, 262165619Sglebius B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, 263165619Sglebius B_SYSTEM_ADDONS_DIRECTORY 264165619Sglebius}; 265165619Sglebius 266165619Sglebiusstatic DriverWatcher sDriverWatcher; 267165619Sglebiusstatic int32 sDriverEventsPending; 268165619Sglebiusstatic DriverEventList sDriverEvents; 269165619Sglebiusstatic mutex sDriverEventsLock = MUTEX_INITIALIZER("driver events"); 270165619Sglebius // inner lock, protects the sDriverEvents list only 271165619Sglebiusstatic DirectoryWatcher sDirectoryWatcher; 272165619Sglebiusstatic DirectoryNodeHash sDirectoryNodeHash; 273165619Sglebiusstatic recursive_lock sLock; 274165619Sglebiusstatic bool sWatching; 275166019Sglebius 276165619Sglebiusstatic DriverTable* sDriverHash; 277165619Sglebius 278165619Sglebius 279165619Sglebius// #pragma mark - driver private 280165619Sglebius 281165619Sglebius 282165619Sglebius/*! Collects all published devices of a driver, compares them to what the 283165619Sglebius driver would publish now, and then publishes/unpublishes the devices 284165619Sglebius as needed. 285165619Sglebius If the driver does not publish any devices anymore, it is unloaded. 286165619Sglebius*/ 287165619Sglebiusstatic status_t 288165619Sglebiusrepublish_driver(legacy_driver* driver) 289165619Sglebius{ 290165619Sglebius if (driver->image < 0) { 291165619Sglebius // The driver is not yet loaded - go through the normal load procedure 292165619Sglebius return load_driver(driver); 293165619Sglebius } 294165619Sglebius 295165619Sglebius // mark all devices 296165619Sglebius DeviceList::Iterator iterator = driver->devices.GetIterator(); 297165619Sglebius while (LegacyDevice* device = iterator.Next()) { 298165619Sglebius device->SetRepublished(false); 299165619Sglebius } 300165619Sglebius 301165619Sglebius // now ask the driver for it's currently published devices 302165619Sglebius const char** devicePaths = driver->publish_devices(); 303165619Sglebius 304165619Sglebius int32 exported = 0; 305165619Sglebius for (; devicePaths != NULL && devicePaths[0]; devicePaths++) { 306165619Sglebius LegacyDevice* device; 307165619Sglebius 308166019Sglebius iterator = driver->devices.GetIterator(); 309165619Sglebius while ((device = iterator.Next()) != NULL) { 310165619Sglebius if (!strncmp(device->Path(), devicePaths[0], B_PATH_NAME_LENGTH)) { 311165619Sglebius // mark device as republished 312165619Sglebius device->SetRepublished(true); 313165619Sglebius exported++; 314165619Sglebius break; 315165619Sglebius } 316165619Sglebius } 317165619Sglebius 318165619Sglebius device_hooks* hooks = driver->find_device(devicePaths[0]); 319165619Sglebius if (hooks == NULL) 320165619Sglebius continue; 321165619Sglebius 322165619Sglebius if (device != NULL) { 323165619Sglebius // update hooks 324165619Sglebius device->SetHooks(hooks); 325165619Sglebius continue; 326165619Sglebius } 327165619Sglebius 328165619Sglebius // the device was not present before -> publish it now 329165619Sglebius TRACE(("devfs: publishing new device \"%s\"\n", devicePaths[0])); 330165619Sglebius device = new(std::nothrow) LegacyDevice(driver, devicePaths[0], hooks); 331165619Sglebius if (device != NULL && device->InitCheck() == B_OK 332165619Sglebius && devfs_publish_device(devicePaths[0], device) == B_OK) { 333165619Sglebius driver->devices.Add(device); 334165619Sglebius exported++; 335165619Sglebius } else 336165619Sglebius delete device; 337165619Sglebius } 338165619Sglebius 339165619Sglebius // remove all devices that weren't republished 340165619Sglebius iterator = driver->devices.GetIterator(); 341165619Sglebius while (LegacyDevice* device = iterator.Next()) { 342165619Sglebius if (device->Republished()) 343165619Sglebius continue; 344165619Sglebius 345165619Sglebius TRACE(("devfs: unpublishing no more present \"%s\"\n", device->Path())); 346165619Sglebius iterator.Remove(); 347165619Sglebius device->SetRemovedFromParent(true); 348165619Sglebius 349165619Sglebius devfs_unpublish_device(device, true); 350165619Sglebius } 351165619Sglebius 352165619Sglebius if (exported == 0 && driver->devices_used == 0 && gBootDevice >= 0) { 353165619Sglebius TRACE(("devfs: driver \"%s\" does not publish any more nodes and is " 354165619Sglebius "unloaded\n", driver->path)); 355165619Sglebius unload_driver(driver); 356165619Sglebius } 357165619Sglebius 358165619Sglebius return B_OK; 359165619Sglebius} 360165619Sglebius 361165619Sglebius 362165619Sglebiusstatic status_t 363165619Sglebiusload_driver(legacy_driver* driver) 364165619Sglebius{ 365165619Sglebius status_t (*init_hardware)(void); 366165619Sglebius status_t (*init_driver)(void); 367165619Sglebius status_t status; 368165619Sglebius 369165619Sglebius driver->binary_updated = false; 370165619Sglebius 371165619Sglebius // load the module 372165619Sglebius image_id image = driver->image; 373165619Sglebius if (image < 0) { 374165619Sglebius image = load_kernel_add_on(driver->path); 375165619Sglebius if (image < 0) 376165619Sglebius return image; 377165619Sglebius } 378165619Sglebius 379165619Sglebius // For a valid device driver the following exports are required 380165619Sglebius 381165619Sglebius int32* apiVersion; 382165619Sglebius if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, 383165619Sglebius (void**)&apiVersion) == B_OK) { 384165619Sglebius#if B_CUR_DRIVER_API_VERSION != 2 385165619Sglebius // just in case someone decides to bump up the api version 386165619Sglebius#error Add checks here for new vs old api version! 387165619Sglebius#endif 388165619Sglebius if (*apiVersion > B_CUR_DRIVER_API_VERSION) { 389165619Sglebius dprintf("devfs: \"%s\" api_version %" B_PRId32 " not handled\n", 390165619Sglebius driver->name, *apiVersion); 391165619Sglebius status = B_BAD_VALUE; 392165619Sglebius goto error1; 393165619Sglebius } 394165619Sglebius if (*apiVersion < 1) { 395165619Sglebius dprintf("devfs: \"%s\" api_version invalid\n", driver->name); 396165619Sglebius status = B_BAD_VALUE; 397165619Sglebius goto error1; 398165619Sglebius } 399165619Sglebius 400165619Sglebius driver->api_version = *apiVersion; 401165619Sglebius } else 402166019Sglebius dprintf("devfs: \"%s\" api_version missing\n", driver->name); 403187405Smav 404243882Sglebius if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, 405187405Smav (void**)&driver->publish_devices) != B_OK 406187405Smav || get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, 407187405Smav (void**)&driver->find_device) != B_OK) { 408187405Smav dprintf("devfs: \"%s\" mandatory driver symbol(s) missing!\n", 409187405Smav driver->name); 410165619Sglebius status = B_BAD_VALUE; 411165619Sglebius goto error1; 412165619Sglebius } 413165619Sglebius 414165619Sglebius // Init the driver 415165619Sglebius 416165619Sglebius if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT, 417165619Sglebius (void**)&init_hardware) == B_OK 418165619Sglebius && (status = init_hardware()) != B_OK) { 419165619Sglebius TRACE(("%s: init_hardware() failed: %s\n", driver->name, 420165619Sglebius strerror(status))); 421165619Sglebius status = ENXIO; 422165619Sglebius goto error1; 423165619Sglebius } 424165619Sglebius 425165619Sglebius if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT, 426165619Sglebius (void**)&init_driver) == B_OK 427165619Sglebius && (status = init_driver()) != B_OK) { 428165619Sglebius TRACE(("%s: init_driver() failed: %s\n", driver->name, 429165619Sglebius strerror(status))); 430165619Sglebius status = ENXIO; 431165619Sglebius goto error2; 432165619Sglebius } 433165619Sglebius 434165619Sglebius // resolve and cache those for the driver unload code 435165619Sglebius if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT, 436165619Sglebius (void**)&driver->uninit_driver) != B_OK) 437165619Sglebius driver->uninit_driver = NULL; 438165619Sglebius if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT, 439165619Sglebius (void**)&driver->uninit_hardware) != B_OK) 440165619Sglebius driver->uninit_hardware = NULL; 441165619Sglebius 442165619Sglebius // The driver has successfully been initialized, now we can 443165619Sglebius // finally publish its device entries 444165619Sglebius 445187405Smav driver->image = image; 446187405Smav return republish_driver(driver); 447187405Smav 448187405Smaverror2: 449187405Smav if (driver->uninit_hardware) 450187405Smav driver->uninit_hardware(); 451187405Smav 452187405Smaverror1: 453165619Sglebius if (driver->image < 0) { 454165619Sglebius unload_kernel_add_on(image); 455165619Sglebius driver->image = status; 456165619Sglebius } 457165619Sglebius 458165619Sglebius return status; 459165619Sglebius} 460165619Sglebius 461165619Sglebius 462165619Sglebiusstatic status_t 463165619Sglebiusunload_driver(legacy_driver* driver) 464165619Sglebius{ 465165619Sglebius if (driver->image < 0) { 466165619Sglebius // driver is not currently loaded 467165619Sglebius return B_NO_INIT; 468165619Sglebius } 469165619Sglebius 470165619Sglebius if (driver->uninit_driver) 471165619Sglebius driver->uninit_driver(); 472165619Sglebius 473165619Sglebius if (driver->uninit_hardware) 474166019Sglebius driver->uninit_hardware(); 475165619Sglebius 476165619Sglebius unload_kernel_add_on(driver->image); 477165619Sglebius driver->image = -1; 478165619Sglebius driver->binary_updated = false; 479165619Sglebius driver->find_device = NULL; 480165619Sglebius driver->publish_devices = NULL; 481187405Smav driver->uninit_driver = NULL; 482243882Sglebius driver->uninit_hardware = NULL; 483187405Smav 484187405Smav return B_OK; 485187405Smav} 486187405Smav 487187405Smav 488165619Sglebius/*! Unpublishes all devices belonging to the \a driver. */ 489165619Sglebiusstatic void 490165619Sglebiusunpublish_driver(legacy_driver* driver) 491165619Sglebius{ 492166019Sglebius while (LegacyDevice* device = driver->devices.RemoveHead()) { 493165619Sglebius device->SetRemovedFromParent(true); 494165619Sglebius devfs_unpublish_device(device, true); 495165619Sglebius } 496165619Sglebius} 497165619Sglebius 498165619Sglebius 499165619Sglebiusstatic void 500165619Sglebiuschange_driver_watcher(dev_t device, ino_t node, bool add) 501165619Sglebius{ 502165619Sglebius if (device == -1) 503165619Sglebius return; 504165619Sglebius 505165619Sglebius driver_event* event = new (std::nothrow) driver_event( 506165619Sglebius add ? kAddWatcher : kRemoveWatcher); 507187405Smav if (event == NULL) 508165619Sglebius return; 509165619Sglebius 510165619Sglebius event->node.device = device; 511165619Sglebius event->node.node = node; 512165619Sglebius 513165619Sglebius MutexLocker _(sDriverEventsLock); 514165619Sglebius sDriverEvents.Add(event); 515165619Sglebius 516165619Sglebius atomic_add(&sDriverEventsPending, 1); 517165619Sglebius} 518165619Sglebius 519165619Sglebius 520165619Sglebiusstatic int32 521165619Sglebiusget_priority(const char* path) 522165619Sglebius{ 523165619Sglebius // TODO: would it be better to initialize a static structure here 524165619Sglebius // using find_directory()? 525165619Sglebius const directory_which whichPath[] = { 526187405Smav B_SYSTEM_DIRECTORY, 527165619Sglebius B_SYSTEM_NONPACKAGED_DIRECTORY, 528165619Sglebius B_USER_DIRECTORY 529165619Sglebius }; 530165619Sglebius KPath pathBuffer; 531165619Sglebius 532165619Sglebius for (uint32 index = 0; index < sizeof(whichPath) / sizeof(whichPath[0]); 533187405Smav index++) { 534187405Smav if (__find_directory(whichPath[index], gBootDevice, false, 535187405Smav pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { 536165619Sglebius pathBuffer.UnlockBuffer(); 537165619Sglebius if (!strncmp(pathBuffer.Path(), path, pathBuffer.BufferSize())) 538187405Smav return index; 539187405Smav } else 540187405Smav pathBuffer.UnlockBuffer(); 541165619Sglebius } 542165619Sglebius 543165619Sglebius return -1; 544165619Sglebius} 545165619Sglebius 546165619Sglebius 547165619Sglebiusstatic const char* 548165619Sglebiusget_leaf(const char* path) 549165619Sglebius{ 550165619Sglebius const char* name = strrchr(path, '/'); 551165619Sglebius if (name == NULL) 552165619Sglebius return path; 553165619Sglebius 554165619Sglebius return name + 1; 555165619Sglebius} 556165619Sglebius 557165619Sglebius 558165619Sglebiusstatic legacy_driver* 559165619Sglebiusfind_driver(dev_t device, ino_t node) 560165619Sglebius{ 561165619Sglebius DriverTable::Iterator iterator(sDriverHash); 562165619Sglebius while (iterator.HasNext()) { 563165619Sglebius legacy_driver* driver = iterator.Next(); 564165619Sglebius if (driver->device == device && driver->node == node) 565165619Sglebius return driver; 566165619Sglebius } 567165619Sglebius 568165619Sglebius return NULL; 569165619Sglebius} 570165619Sglebius 571165619Sglebius 572165619Sglebiusstatic status_t 573165619Sglebiusadd_driver(const char* path, image_id image) 574165619Sglebius{ 575165619Sglebius // Check if we already know this driver 576165619Sglebius 577165619Sglebius struct stat stat; 578165619Sglebius if (image >= 0) { 579165619Sglebius // The image ID should be a small number and hopefully the boot FS 580165619Sglebius // doesn't use small negative values -- if it is inode based, we should 581165619Sglebius // be relatively safe. 582165619Sglebius stat.st_dev = -1; 583165619Sglebius stat.st_ino = -1; 584165619Sglebius } else { 585175706Smav if (::stat(path, &stat) != 0) 586165619Sglebius return errno; 587165619Sglebius } 588165619Sglebius 589165619Sglebius int32 priority = get_priority(path); 590165619Sglebius 591165619Sglebius RecursiveLocker _(sLock); 592165619Sglebius 593175706Smav legacy_driver* driver = sDriverHash->Lookup(get_leaf(path)); 594165619Sglebius if (driver != NULL) { 595165619Sglebius // we know this driver 596175706Smav if (strcmp(driver->path, path) != 0) { 597165619Sglebius // TODO: do properly, but for now we just update the path if it 598165619Sglebius // isn't the same anymore so rescanning of drivers will work in 599165619Sglebius // case this driver was loaded so early that it has a boot module 600165619Sglebius // path and not a proper driver path 601165619Sglebius free((char*)driver->path); 602165619Sglebius driver->path = strdup(path); 603165619Sglebius driver->name = get_leaf(driver->path); 604165619Sglebius driver->binary_updated = true; 605165619Sglebius } 606165619Sglebius 607165619Sglebius // TODO: check if this driver is a different one and has precendence 608165619Sglebius // (ie. common supersedes system). 609165619Sglebius //dprintf("new driver has priority %ld, old %ld\n", priority, driver->priority); 610165619Sglebius if (priority >= driver->priority) { 611165619Sglebius driver->binary_updated = true; 612165619Sglebius return B_OK; 613165619Sglebius } 614165619Sglebius 615165619Sglebius // TODO: test for changes here and/or via node monitoring and reload 616165619Sglebius // the driver if necessary 617165619Sglebius if (driver->image < B_OK) 618165619Sglebius return driver->image; 619165619Sglebius 620175706Smav return B_OK; 621165619Sglebius } 622165619Sglebius 623165619Sglebius // we don't know this driver, create a new entry for it 624165619Sglebius 625165619Sglebius driver = (legacy_driver*)malloc(sizeof(legacy_driver)); 626165619Sglebius if (driver == NULL) 627175706Smav return B_NO_MEMORY; 628165619Sglebius 629165619Sglebius driver->path = strdup(path); 630175706Smav if (driver->path == NULL) { 631165619Sglebius free(driver); 632165619Sglebius return B_NO_MEMORY; 633165619Sglebius } 634165619Sglebius 635165619Sglebius driver->name = get_leaf(driver->path); 636165619Sglebius driver->device = stat.st_dev; 637165619Sglebius driver->node = stat.st_ino; 638165619Sglebius driver->image = image; 639165619Sglebius driver->last_modified = stat.st_mtim; 640165619Sglebius driver->devices_used = 0; 641165619Sglebius driver->binary_updated = false; 642165619Sglebius driver->priority = priority; 643165619Sglebius 644165619Sglebius driver->api_version = 1; 645165619Sglebius driver->find_device = NULL; 646165619Sglebius driver->publish_devices = NULL; 647165619Sglebius driver->uninit_driver = NULL; 648165619Sglebius driver->uninit_hardware = NULL; 649165619Sglebius new(&driver->devices) DeviceList; 650165619Sglebius 651165619Sglebius sDriverHash->Insert(driver); 652165619Sglebius if (stat.st_dev > 0) 653165619Sglebius change_driver_watcher(stat.st_dev, stat.st_ino, true); 654165619Sglebius 655165619Sglebius // Even if loading the driver fails - its entry will stay with us 656165619Sglebius // so that we don't have to go through it again 657165619Sglebius return load_driver(driver); 658165619Sglebius} 659165619Sglebius 660165619Sglebius 661165619Sglebius/*! This is no longer part of the public kernel API, so we just export the 662165619Sglebius symbol 663165619Sglebius*/ 664165619Sglebiusextern "C" status_t load_driver_symbols(const char* driverName); 665165619Sglebiusstatus_t 666165619Sglebiusload_driver_symbols(const char* driverName) 667165619Sglebius{ 668165619Sglebius // This is done globally for the whole kernel via the settings file. 669165619Sglebius // We don't have to do anything here. 670165619Sglebius 671165619Sglebius return B_OK; 672165619Sglebius} 673165619Sglebius 674165619Sglebius 675165619Sglebiusstatic status_t 676165619Sglebiusreload_driver(legacy_driver* driver) 677165619Sglebius{ 678165619Sglebius dprintf("devfs: reload driver \"%s\" (%" B_PRIdDEV ", %" B_PRIdINO ")\n", 679165619Sglebius driver->name, driver->device, driver->node); 680165619Sglebius 681165619Sglebius unload_driver(driver); 682165619Sglebius 683165619Sglebius struct stat stat; 684165619Sglebius if (::stat(driver->path, &stat) == 0 685165619Sglebius && (stat.st_dev != driver->device || stat.st_ino != driver->node)) { 686165619Sglebius // The driver file has been changed, so we need to update its listener 687165619Sglebius change_driver_watcher(driver->device, driver->node, false); 688165619Sglebius 689165619Sglebius driver->device = stat.st_dev; 690165619Sglebius driver->node = stat.st_ino; 691165619Sglebius 692165619Sglebius change_driver_watcher(driver->device, driver->node, true); 693165619Sglebius } 694165619Sglebius 695165619Sglebius status_t status = load_driver(driver); 696165619Sglebius if (status != B_OK) 697165619Sglebius unpublish_driver(driver); 698165619Sglebius 699165619Sglebius return status; 700165619Sglebius} 701165619Sglebius 702165619Sglebius 703165619Sglebiusstatic void 704165619Sglebiushandle_driver_events(void* /*_fs*/, int /*iteration*/) 705165619Sglebius{ 706165619Sglebius if (atomic_and(&sDriverEventsPending, 0) == 0) 707165619Sglebius return; 708165619Sglebius 709165619Sglebius // something happened, let's see what it was 710165619Sglebius 711165619Sglebius while (true) { 712165619Sglebius MutexLocker eventLocker(sDriverEventsLock); 713165619Sglebius 714165619Sglebius driver_event* event = sDriverEvents.RemoveHead(); 715165619Sglebius if (event == NULL) 716 break; 717 718 eventLocker.Unlock(); 719 TRACE(("driver event %p, type %d\n", event, event->type)); 720 721 switch (event->type) { 722 case kAddDriver: 723 { 724 // Add new drivers 725 RecursiveLocker locker(sLock); 726 TRACE((" add driver %p\n", event->path)); 727 728 legacy_driver* driver = sDriverHash->Lookup( 729 get_leaf(event->path)); 730 if (driver == NULL) 731 legacy_driver_add(event->path); 732 else if (get_priority(event->path) >= driver->priority) 733 driver->binary_updated = true; 734 break; 735 } 736 737 case kRemoveDriver: 738 { 739 // Mark removed drivers as updated 740 RecursiveLocker locker(sLock); 741 TRACE((" remove driver %p\n", event->path)); 742 743 legacy_driver* driver = sDriverHash->Lookup( 744 get_leaf(event->path)); 745 if (driver != NULL 746 && get_priority(event->path) >= driver->priority) 747 driver->binary_updated = true; 748 break; 749 } 750 751 case kAddWatcher: 752 TRACE((" add watcher %ld:%lld\n", event->node.device, 753 event->node.node)); 754 add_node_listener(event->node.device, event->node.node, 755 B_WATCH_STAT | B_WATCH_NAME, sDriverWatcher); 756 break; 757 758 case kRemoveWatcher: 759 TRACE((" remove watcher %ld:%lld\n", event->node.device, 760 event->node.node)); 761 remove_node_listener(event->node.device, event->node.node, 762 sDriverWatcher); 763 break; 764 } 765 766 delete event; 767 } 768 769 // Reload updated drivers 770 771 RecursiveLocker locker(sLock); 772 773 DriverTable::Iterator iterator(sDriverHash); 774 while (iterator.HasNext()) { 775 legacy_driver* driver = iterator.Next(); 776 777 if (!driver->binary_updated || driver->devices_used != 0) 778 continue; 779 780 // try to reload the driver 781 reload_driver(driver); 782 } 783 784 locker.Unlock(); 785} 786 787 788// #pragma mark - DriverWatcher 789 790 791DriverWatcher::DriverWatcher() 792{ 793} 794 795 796DriverWatcher::~DriverWatcher() 797{ 798} 799 800 801void 802DriverWatcher::EventOccurred(NotificationService& service, 803 const KMessage* event) 804{ 805 int32 opcode = event->GetInt32("opcode", -1); 806 if (opcode != B_STAT_CHANGED 807 || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0) 808 return; 809 810 RecursiveLocker locker(sLock); 811 812 legacy_driver* driver = find_driver(event->GetInt32("device", -1), 813 event->GetInt64("node", 0)); 814 if (driver == NULL) 815 return; 816 817 driver->binary_updated = true; 818 819 if (driver->devices_used == 0) { 820 // trigger a reload of the driver 821 atomic_add(&sDriverEventsPending, 1); 822 } else { 823 // driver is in use right now 824 dprintf("devfs: changed driver \"%s\" is still in use\n", driver->name); 825 } 826} 827 828 829static void 830dump_driver(legacy_driver* driver) 831{ 832 kprintf("DEVFS DRIVER: %p\n", driver); 833 kprintf(" name: %s\n", driver->name); 834 kprintf(" path: %s\n", driver->path); 835 kprintf(" image: %" B_PRId32 "\n", driver->image); 836 kprintf(" device: %" B_PRIdDEV "\n", driver->device); 837 kprintf(" node: %" B_PRIdINO "\n", driver->node); 838 kprintf(" last modified: %" B_PRIdTIME ".%ld\n", driver->last_modified.tv_sec, 839 driver->last_modified.tv_nsec); 840 kprintf(" devs used: %" B_PRIu32 "\n", driver->devices_used); 841 kprintf(" devs published: %" B_PRId32 "\n", driver->devices.Count()); 842 kprintf(" binary updated: %d\n", driver->binary_updated); 843 kprintf(" priority: %" B_PRId32 "\n", driver->priority); 844 kprintf(" api version: %" B_PRId32 "\n", driver->api_version); 845 kprintf(" hooks: find_device %p, publish_devices %p\n" 846 " uninit_driver %p, uninit_hardware %p\n", 847 driver->find_device, driver->publish_devices, driver->uninit_driver, 848 driver->uninit_hardware); 849} 850 851 852static int 853dump_device(int argc, char** argv) 854{ 855 if (argc < 2 || !strcmp(argv[1], "--help")) { 856 kprintf("usage: %s [device]\n", argv[0]); 857 return 0; 858 } 859 860 LegacyDevice* device = (LegacyDevice*)parse_expression(argv[1]); 861 862 kprintf("LEGACY DEVICE: %p\n", device); 863 kprintf(" path: %s\n", device->Path()); 864 kprintf(" hooks: %p\n", device->Hooks()); 865 device_hooks* hooks = device->Hooks(); 866 kprintf(" close() %p\n", hooks->close); 867 kprintf(" free() %p\n", hooks->free); 868 kprintf(" control() %p\n", hooks->control); 869 kprintf(" read() %p\n", hooks->read); 870 kprintf(" write() %p\n", hooks->write); 871 kprintf(" select() %p\n", hooks->select); 872 kprintf(" deselect() %p\n", hooks->deselect); 873 dump_driver(device->Driver()); 874 875 return 0; 876} 877 878 879static int 880dump_driver(int argc, char** argv) 881{ 882 if (argc < 2) { 883 // print list of all drivers 884 kprintf("address image used publ. pri name\n"); 885 DriverTable::Iterator iterator(sDriverHash); 886 while (iterator.HasNext()) { 887 legacy_driver* driver = iterator.Next(); 888 889 kprintf("%p %5" B_PRId32 " %3" B_PRIu32 " %5" B_PRId32 " %c " 890 "%3" B_PRId32 " %s\n", driver, 891 driver->image < 0 ? -1 : driver->image, 892 driver->devices_used, driver->devices.Count(), 893 driver->binary_updated ? 'U' : ' ', driver->priority, 894 driver->name); 895 } 896 897 return 0; 898 } 899 900 if (!strcmp(argv[1], "--help")) { 901 kprintf("usage: %s [name]\n", argv[0]); 902 return 0; 903 } 904 905 legacy_driver* driver = sDriverHash->Lookup(argv[1]); 906 if (driver == NULL) { 907 kprintf("Driver named \"%s\" not found.\n", argv[1]); 908 return 0; 909 } 910 911 dump_driver(driver); 912 return 0; 913} 914 915 916// #pragma mark - 917 918 919DirectoryIterator::DirectoryIterator(const char* path, const char* subPath, 920 bool recursive) 921 : 922 fDirectory(NULL), 923 fBasePath(NULL), 924 fCurrentName(NULL) 925{ 926 SetTo(path, subPath, recursive); 927} 928 929 930DirectoryIterator::~DirectoryIterator() 931{ 932 Unset(); 933} 934 935 936void 937DirectoryIterator::SetTo(const char* path, const char* subPath, bool recursive) 938{ 939 Unset(); 940 fRecursive = recursive; 941 942 if (path == NULL) { 943 // add default paths 944 KPath pathBuffer; 945 946 bool disableUserAddOns = get_safemode_boolean( 947 B_SAFEMODE_DISABLE_USER_ADD_ONS, false); 948 949 for (uint32 i = 0; i < sizeof(kDriverPaths) / sizeof(kDriverPaths[0]); i++) { 950 if (i < 3 && disableUserAddOns) 951 continue; 952 953 if (__find_directory(kDriverPaths[i], gBootDevice, true, 954 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { 955 pathBuffer.UnlockBuffer(); 956 pathBuffer.Append("kernel"); 957 AddPath(pathBuffer.Path(), subPath); 958 } else 959 pathBuffer.UnlockBuffer(); 960 } 961 } else 962 AddPath(path, subPath); 963} 964 965 966status_t 967DirectoryIterator::GetNext(KPath& path, struct stat& stat) 968{ 969next_directory: 970 while (fDirectory == NULL) { 971 delete fBasePath; 972 fBasePath = NULL; 973 974 if (!fPaths.Pop(&fBasePath)) 975 return B_ENTRY_NOT_FOUND; 976 977 fDirectory = opendir(fBasePath->Path()); 978 } 979 980next_entry: 981 struct dirent* dirent = readdir(fDirectory); 982 if (dirent == NULL) { 983 // get over to next directory on the stack 984 closedir(fDirectory); 985 fDirectory = NULL; 986 987 goto next_directory; 988 } 989 990 if (!strcmp(dirent->d_name, "..") || !strcmp(dirent->d_name, ".")) 991 goto next_entry; 992 993 fCurrentName = dirent->d_name; 994 995 path.SetTo(fBasePath->Path()); 996 path.Append(fCurrentName); 997 998 if (::stat(path.Path(), &stat) != 0) 999 goto next_entry; 1000 1001 if (S_ISDIR(stat.st_mode) && fRecursive) { 1002 KPath* nextPath = new(nothrow) KPath(path); 1003 if (!nextPath) 1004 return B_NO_MEMORY; 1005 if (fPaths.Push(nextPath) != B_OK) 1006 return B_NO_MEMORY; 1007 1008 goto next_entry; 1009 } 1010 1011 return B_OK; 1012} 1013 1014 1015void 1016DirectoryIterator::Unset() 1017{ 1018 if (fDirectory != NULL) { 1019 closedir(fDirectory); 1020 fDirectory = NULL; 1021 } 1022 1023 delete fBasePath; 1024 fBasePath = NULL; 1025 1026 KPath* path; 1027 while (fPaths.Pop(&path)) 1028 delete path; 1029} 1030 1031 1032void 1033DirectoryIterator::AddPath(const char* basePath, const char* subPath) 1034{ 1035 KPath* path = new(nothrow) KPath(basePath); 1036 if (!path) 1037 panic("out of memory"); 1038 if (subPath != NULL) 1039 path->Append(subPath); 1040 1041 fPaths.Push(path); 1042} 1043 1044 1045// #pragma mark - 1046 1047 1048DirectoryWatcher::DirectoryWatcher() 1049{ 1050} 1051 1052 1053DirectoryWatcher::~DirectoryWatcher() 1054{ 1055} 1056 1057 1058void 1059DirectoryWatcher::EventOccurred(NotificationService& service, 1060 const KMessage* event) 1061{ 1062 int32 opcode = event->GetInt32("opcode", -1); 1063 dev_t device = event->GetInt32("device", -1); 1064 ino_t directory = event->GetInt64("directory", -1); 1065 const char* name = event->GetString("name", NULL); 1066 1067 if (opcode == B_ENTRY_MOVED) { 1068 // Determine whether it's a move within, out of, or into one 1069 // of our watched directories. 1070 ino_t from = event->GetInt64("from directory", -1); 1071 ino_t to = event->GetInt64("to directory", -1); 1072 if (sDirectoryNodeHash.Lookup(&from) == NULL) { 1073 directory = to; 1074 opcode = B_ENTRY_CREATED; 1075 } else if (sDirectoryNodeHash.Lookup(&to) == NULL) { 1076 directory = from; 1077 opcode = B_ENTRY_REMOVED; 1078 } else { 1079 // Move within, don't do anything for now 1080 // TODO: adjust driver priority if necessary 1081 return; 1082 } 1083 } 1084 1085 KPath path(B_PATH_NAME_LENGTH + 1); 1086 if (path.InitCheck() != B_OK || vfs_entry_ref_to_path(device, directory, 1087 name, true, path.LockBuffer(), path.BufferSize()) != B_OK) 1088 return; 1089 1090 path.UnlockBuffer(); 1091 1092 dprintf("driver \"%s\" %s\n", path.Leaf(), 1093 opcode == B_ENTRY_CREATED ? "added" : "removed"); 1094 1095 driver_event* driverEvent = new(std::nothrow) driver_event( 1096 opcode == B_ENTRY_CREATED ? kAddDriver : kRemoveDriver); 1097 if (driverEvent == NULL) 1098 return; 1099 1100 strlcpy(driverEvent->path, path.Path(), sizeof(driverEvent->path)); 1101 1102 MutexLocker _(sDriverEventsLock); 1103 sDriverEvents.Add(driverEvent); 1104 atomic_add(&sDriverEventsPending, 1); 1105} 1106 1107 1108// #pragma mark - 1109 1110 1111static void 1112start_watching(const char* base, const char* sub) 1113{ 1114 KPath path(base); 1115 path.Append(sub); 1116 1117 // TODO: create missing directories? 1118 struct stat stat; 1119 if (::stat(path.Path(), &stat) != 0) 1120 return; 1121 1122 add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, 1123 sDirectoryWatcher); 1124 1125 directory_node_entry* entry = new(std::nothrow) directory_node_entry; 1126 if (entry != NULL) { 1127 entry->node = stat.st_ino; 1128 sDirectoryNodeHash.Insert(entry); 1129 } 1130} 1131 1132 1133static struct driver_entry* 1134new_driver_entry(const char* path, dev_t device, ino_t node) 1135{ 1136 driver_entry* entry = new(std::nothrow) driver_entry; 1137 if (entry == NULL) 1138 return NULL; 1139 1140 entry->path = strdup(path); 1141 if (entry->path == NULL) { 1142 delete entry; 1143 return NULL; 1144 } 1145 1146 entry->device = device; 1147 entry->node = node; 1148 entry->busses = 0; 1149 return entry; 1150} 1151 1152 1153/*! Iterates over the given list and tries to load all drivers in that list. 1154 The list is emptied and freed during the traversal. 1155*/ 1156static status_t 1157try_drivers(DriverEntryList& list) 1158{ 1159 while (true) { 1160 driver_entry* entry = list.RemoveHead(); 1161 if (entry == NULL) 1162 break; 1163 1164 image_id image = load_kernel_add_on(entry->path); 1165 if (image >= 0) { 1166 // check if it's an old-style driver 1167 if (legacy_driver_add(entry->path) == B_OK) { 1168 // we have a driver 1169 dprintf("loaded driver %s\n", entry->path); 1170 } 1171 1172 unload_kernel_add_on(image); 1173 } 1174 1175 free(entry->path); 1176 delete entry; 1177 } 1178 1179 return B_OK; 1180} 1181 1182 1183static status_t 1184probe_for_drivers(const char* type) 1185{ 1186 TRACE(("probe_for_drivers(type = %s)\n", type)); 1187 1188 if (gBootDevice < 0) 1189 return B_OK; 1190 1191 DriverEntryList drivers; 1192 1193 // build list of potential drivers for that type 1194 1195 DirectoryIterator iterator(NULL, type, false); 1196 struct stat stat; 1197 KPath path; 1198 1199 while (iterator.GetNext(path, stat) == B_OK) { 1200 if (S_ISDIR(stat.st_mode)) { 1201 add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, 1202 sDirectoryWatcher); 1203 1204 directory_node_entry* entry 1205 = new(std::nothrow) directory_node_entry; 1206 if (entry != NULL) { 1207 entry->node = stat.st_ino; 1208 sDirectoryNodeHash.Insert(entry); 1209 } 1210 1211 // We need to make sure that drivers in ie. "audio/raw/" can 1212 // be found as well - therefore, we must make sure that "audio" 1213 // exists on /dev. 1214 1215 size_t length = strlen("drivers/dev"); 1216 if (strncmp(type, "drivers/dev", length)) 1217 continue; 1218 1219 path.SetTo(type); 1220 path.Append(iterator.CurrentName()); 1221 devfs_publish_directory(path.Path() + length + 1); 1222 continue; 1223 } 1224 1225 driver_entry* entry = new_driver_entry(path.Path(), stat.st_dev, 1226 stat.st_ino); 1227 if (entry == NULL) 1228 return B_NO_MEMORY; 1229 1230 TRACE(("found potential driver: %s\n", path.Path())); 1231 drivers.Add(entry); 1232 } 1233 1234 if (drivers.IsEmpty()) 1235 return B_OK; 1236 1237 // ToDo: do something with the remaining drivers... :) 1238 try_drivers(drivers); 1239 return B_OK; 1240} 1241 1242 1243// #pragma mark - LegacyDevice 1244 1245 1246LegacyDevice::LegacyDevice(legacy_driver* driver, const char* path, 1247 device_hooks* hooks) 1248 : 1249 fDriver(driver), 1250 fRepublished(true), 1251 fRemovedFromParent(false) 1252{ 1253 fDeviceModule = (device_module_info*)malloc(sizeof(device_module_info)); 1254 if (fDeviceModule != NULL) 1255 memset(fDeviceModule, 0, sizeof(device_module_info)); 1256 1257 fDeviceData = this; 1258 fPath = strdup(path); 1259 1260 SetHooks(hooks); 1261} 1262 1263 1264LegacyDevice::~LegacyDevice() 1265{ 1266 free(fDeviceModule); 1267 free((char*)fPath); 1268} 1269 1270 1271status_t 1272LegacyDevice::InitCheck() const 1273{ 1274 return fDeviceModule != NULL && fPath != NULL ? B_OK : B_NO_MEMORY; 1275} 1276 1277 1278status_t 1279LegacyDevice::InitDevice() 1280{ 1281 RecursiveLocker _(sLock); 1282 1283 if (fInitialized++ > 0) 1284 return B_OK; 1285 1286 if (fDriver != NULL && fDriver->devices_used == 0 1287 && (fDriver->image < 0 || fDriver->binary_updated)) { 1288 status_t status = reload_driver(fDriver); 1289 if (status < B_OK) 1290 return status; 1291 } 1292 1293 if (fDriver != NULL) 1294 fDriver->devices_used++; 1295 1296 return B_OK; 1297} 1298 1299 1300void 1301LegacyDevice::UninitDevice() 1302{ 1303 RecursiveLocker _(sLock); 1304 1305 if (fInitialized-- > 1) 1306 return; 1307 1308 if (fDriver != NULL) { 1309 if (--fDriver->devices_used == 0 && fDriver->devices.IsEmpty()) 1310 unload_driver(fDriver); 1311 fDriver = NULL; 1312 } 1313} 1314 1315 1316void 1317LegacyDevice::Removed() 1318{ 1319 RecursiveLocker _(sLock); 1320 1321 if (!fRemovedFromParent && fDriver != NULL) 1322 fDriver->devices.Remove(this); 1323 1324 delete this; 1325} 1326 1327 1328status_t 1329LegacyDevice::Control(void* _cookie, int32 op, void* buffer, size_t length) 1330{ 1331 switch (op) { 1332 case B_GET_DRIVER_FOR_DEVICE: 1333 if (length != 0 && length <= strlen(fDriver->path)) 1334 return ERANGE; 1335 return user_strlcpy(static_cast<char*>(buffer), fDriver->path, length); 1336 default: 1337 return AbstractModuleDevice::Control(_cookie, op, buffer, length); 1338 } 1339} 1340 1341 1342void 1343LegacyDevice::SetHooks(device_hooks* hooks) 1344{ 1345 // TODO: setup compatibility layer! 1346 fHooks = hooks; 1347 1348 fDeviceModule->close = hooks->close; 1349 fDeviceModule->free = hooks->free; 1350 fDeviceModule->control = hooks->control; 1351 fDeviceModule->read = hooks->read; 1352 fDeviceModule->write = hooks->write; 1353 1354 if (fDriver == NULL || fDriver->api_version >= 2) { 1355 // According to Be newsletter, vol II, issue 36, 1356 // version 2 added readv/writev, which we don't support, but also 1357 // select/deselect. 1358 if (hooks->select != NULL) { 1359 // Note we set the module's select to a non-null value to indicate 1360 // that we have select. HasSelect() will therefore return the 1361 // correct answer. As Select() is virtual our compatibility 1362 // version below is going to be called though, that redirects to 1363 // the proper select hook, so it is ok to set it to an invalid 1364 // address here. 1365 fDeviceModule->select = (status_t (*)(void*, uint8, selectsync*))~0; 1366 } 1367 1368 fDeviceModule->deselect = hooks->deselect; 1369 } 1370} 1371 1372 1373status_t 1374LegacyDevice::Open(const char* path, int openMode, void** _cookie) 1375{ 1376 return Hooks()->open(path, openMode, _cookie); 1377} 1378 1379 1380status_t 1381LegacyDevice::Select(void* cookie, uint8 event, selectsync* sync) 1382{ 1383 return Hooks()->select(cookie, event, 0, sync); 1384} 1385 1386 1387// #pragma mark - kernel private API 1388 1389 1390extern "C" void 1391legacy_driver_add_preloaded(kernel_args* args) 1392{ 1393 // NOTE: This function does not exit in case of error, since it 1394 // needs to unload the images then. Also the return code of 1395 // the path operations is kept separate from the add_driver() 1396 // success, so that even if add_driver() fails for one driver, it 1397 // is still tried for the other drivers. 1398 // NOTE: The initialization success of the path objects is implicitely 1399 // checked by the immediately following functions. 1400 KPath basePath; 1401 status_t status = __find_directory(B_SYSTEM_ADDONS_DIRECTORY, 1402 gBootDevice, false, basePath.LockBuffer(), basePath.BufferSize()); 1403 if (status != B_OK) { 1404 dprintf("legacy_driver_add_preloaded: find_directory() failed: " 1405 "%s\n", strerror(status)); 1406 } 1407 basePath.UnlockBuffer(); 1408 if (status == B_OK) 1409 status = basePath.Append("kernel"); 1410 if (status != B_OK) { 1411 dprintf("legacy_driver_add_preloaded: constructing base driver " 1412 "path failed: %s\n", strerror(status)); 1413 return; 1414 } 1415 1416 struct preloaded_image* image; 1417 for (image = args->preloaded_images; image != NULL; image = image->next) { 1418 if (image->is_module || image->id < 0) 1419 continue; 1420 1421 KPath imagePath(basePath); 1422 status = imagePath.Append(image->name); 1423 1424 // try to add the driver 1425 TRACE(("legacy_driver_add_preloaded: adding driver %s\n", 1426 imagePath.Path())); 1427 1428 if (status == B_OK) 1429 status = add_driver(imagePath.Path(), image->id); 1430 if (status != B_OK) { 1431 dprintf("legacy_driver_add_preloaded: Failed to add \"%s\": %s\n", 1432 (char*)image->name, strerror(status)); 1433 unload_kernel_add_on(image->id); 1434 } 1435 } 1436} 1437 1438 1439extern "C" status_t 1440legacy_driver_add(const char* path) 1441{ 1442 return add_driver(path, -1); 1443} 1444 1445 1446extern "C" status_t 1447legacy_driver_publish(const char* path, device_hooks* hooks) 1448{ 1449 // we don't have a driver, just publish the hooks 1450 LegacyDevice* device = new(std::nothrow) LegacyDevice(NULL, path, hooks); 1451 if (device == NULL) 1452 return B_NO_MEMORY; 1453 1454 status_t status = device->InitCheck(); 1455 if (status == B_OK) 1456 status = devfs_publish_device(path, device); 1457 1458 if (status != B_OK) 1459 delete device; 1460 1461 return status; 1462} 1463 1464 1465extern "C" status_t 1466legacy_driver_rescan(const char* driverName) 1467{ 1468 RecursiveLocker locker(sLock); 1469 1470 legacy_driver* driver = sDriverHash->Lookup(driverName); 1471 if (driver == NULL) 1472 return B_ENTRY_NOT_FOUND; 1473 1474 // Republish the driver's entries 1475 return republish_driver(driver); 1476} 1477 1478 1479extern "C" status_t 1480legacy_driver_probe(const char* subPath) 1481{ 1482 TRACE(("legacy_driver_probe(type = %s)\n", subPath)); 1483 1484 char devicePath[64]; 1485 snprintf(devicePath, sizeof(devicePath), "drivers/dev%s%s", 1486 subPath[0] ? "/" : "", subPath); 1487 1488 if (!sWatching && gBootDevice > 0) { 1489 // We're probing the actual boot volume for the first time, 1490 // let's watch its driver directories for changes 1491 KPath path; 1492 1493 new(&sDirectoryWatcher) DirectoryWatcher; 1494 1495 bool disableUserAddOns = get_safemode_boolean( 1496 B_SAFEMODE_DISABLE_USER_ADD_ONS, false); 1497 1498 for (uint32 i = 0; i < sizeof(kDriverPaths) / sizeof(kDriverPaths[0]); i++) { 1499 if (i < 3 && disableUserAddOns) 1500 continue; 1501 1502 if (__find_directory(kDriverPaths[i], gBootDevice, true, 1503 path.LockBuffer(), path.BufferSize()) == B_OK) { 1504 path.UnlockBuffer(); 1505 path.Append("kernel/drivers"); 1506 1507 start_watching(path.Path(), "bin"); 1508 } else 1509 path.UnlockBuffer(); 1510 } 1511 1512 sWatching = true; 1513 } 1514 1515 return probe_for_drivers(devicePath); 1516} 1517 1518 1519extern "C" status_t 1520legacy_driver_init(void) 1521{ 1522 sDriverHash = new(std::nothrow) DriverTable(); 1523 if (sDriverHash == NULL || sDriverHash->Init(DRIVER_HASH_SIZE) != B_OK) 1524 return B_NO_MEMORY; 1525 1526 recursive_lock_init(&sLock, "legacy driver"); 1527 1528 new(&sDriverWatcher) DriverWatcher; 1529 new(&sDriverEvents) DriverEventList; 1530 1531 register_kernel_daemon(&handle_driver_events, NULL, 10); 1532 // once every second 1533 1534 add_debugger_command("legacy_driver", &dump_driver, 1535 "info about a legacy driver entry"); 1536 add_debugger_command("legacy_device", &dump_device, 1537 "info about a legacy device"); 1538 1539 return B_OK; 1540} 1541