123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- /*
- * Copyright 2007-2008, Haiku Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- * Michael Lotz <mmlr@mlotz.ch>
- */
- #include "haiku_usb.h"
- #include <cstdio>
- #include <Directory.h>
- #include <Entry.h>
- #include <Looper.h>
- #include <Messenger.h>
- #include <Node.h>
- #include <NodeMonitor.h>
- #include <Path.h>
- #include <cstring>
- class WatchedEntry {
- public:
- WatchedEntry(BMessenger *, entry_ref *);
- ~WatchedEntry();
- bool EntryCreated(entry_ref *ref);
- bool EntryRemoved(ino_t node);
- bool InitCheck();
- private:
- BMessenger* fMessenger;
- node_ref fNode;
- bool fIsDirectory;
- USBDevice* fDevice;
- WatchedEntry* fEntries;
- WatchedEntry* fLink;
- bool fInitCheck;
- };
- class RosterLooper : public BLooper {
- public:
- RosterLooper(USBRoster *);
- void Stop();
- virtual void MessageReceived(BMessage *);
- bool InitCheck();
- private:
- USBRoster* fRoster;
- WatchedEntry* fRoot;
- BMessenger* fMessenger;
- bool fInitCheck;
- };
- WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
- : fMessenger(messenger),
- fIsDirectory(false),
- fDevice(NULL),
- fEntries(NULL),
- fLink(NULL),
- fInitCheck(false)
- {
- BEntry entry(ref);
- entry.GetNodeRef(&fNode);
- BDirectory directory;
- if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
- fIsDirectory = true;
- while (directory.GetNextEntry(&entry) >= B_OK) {
- if (entry.GetRef(ref) < B_OK)
- continue;
- WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
- if (child == NULL)
- continue;
- if (child->InitCheck() == false) {
- delete child;
- continue;
- }
- child->fLink = fEntries;
- fEntries = child;
- }
- watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
- }
- else {
- if (strncmp(ref->name, "raw", 3) == 0)
- return;
- BPath path, parent_path;
- entry.GetPath(&path);
- fDevice = new(std::nothrow) USBDevice(path.Path());
- if (fDevice != NULL && fDevice->InitCheck() == true) {
- // Add this new device to each active context's device list
- struct libusb_context *ctx;
- unsigned long session_id = (unsigned long)&fDevice;
- usbi_mutex_lock(&active_contexts_lock);
- for_each_context(ctx) {
- struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev) {
- usbi_dbg(NULL, "using previously allocated device with location %lu", session_id);
- libusb_unref_device(dev);
- continue;
- }
- usbi_dbg(NULL, "allocating new device with location %lu", session_id);
- dev = usbi_alloc_device(ctx, session_id);
- if (!dev) {
- usbi_dbg(NULL, "device allocation failed");
- continue;
- }
- *((USBDevice **)usbi_get_device_priv(dev)) = fDevice;
- // Calculate pseudo-device-address
- int addr, tmp;
- if (strcmp(path.Leaf(), "hub") == 0)
- tmp = 100; //Random Number
- else
- sscanf(path.Leaf(), "%d", &tmp);
- addr = tmp + 1;
- path.GetParent(&parent_path);
- while (strcmp(parent_path.Leaf(), "usb") != 0) {
- sscanf(parent_path.Leaf(), "%d", &tmp);
- addr += tmp + 1;
- parent_path.GetParent(&parent_path);
- }
- sscanf(path.Path(), "/dev/bus/usb/%hhu", &dev->bus_number);
- dev->device_address = addr - (dev->bus_number + 1);
- static_assert(sizeof(dev->device_descriptor) == sizeof(usb_device_descriptor),
- "mismatch between libusb and OS device descriptor sizes");
- memcpy(&dev->device_descriptor, fDevice->Descriptor(), LIBUSB_DT_DEVICE_SIZE);
- usbi_localize_device_descriptor(&dev->device_descriptor);
- if (usbi_sanitize_device(dev) < 0) {
- usbi_dbg(NULL, "device sanitization failed");
- libusb_unref_device(dev);
- continue;
- }
- usbi_connect_device(dev);
- }
- usbi_mutex_unlock(&active_contexts_lock);
- }
- else if (fDevice) {
- delete fDevice;
- fDevice = NULL;
- return;
- }
- }
- fInitCheck = true;
- }
- WatchedEntry::~WatchedEntry()
- {
- if (fIsDirectory) {
- watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
- WatchedEntry *child = fEntries;
- while (child) {
- WatchedEntry *next = child->fLink;
- delete child;
- child = next;
- }
- }
- if (fDevice) {
- // Remove this device from each active context's device list
- struct libusb_context *ctx;
- struct libusb_device *dev;
- unsigned long session_id = (unsigned long)&fDevice;
- usbi_mutex_lock(&active_contexts_lock);
- for_each_context(ctx) {
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev != NULL) {
- usbi_disconnect_device(dev);
- libusb_unref_device(dev);
- } else {
- usbi_dbg(ctx, "device with location %lu not found", session_id);
- }
- }
- usbi_mutex_static_unlock(&active_contexts_lock);
- delete fDevice;
- }
- }
- bool
- WatchedEntry::EntryCreated(entry_ref *ref)
- {
- if (!fIsDirectory)
- return false;
- if (ref->directory != fNode.node) {
- WatchedEntry *child = fEntries;
- while (child) {
- if (child->EntryCreated(ref))
- return true;
- child = child->fLink;
- }
- return false;
- }
- WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
- if (child == NULL)
- return false;
- child->fLink = fEntries;
- fEntries = child;
- return true;
- }
- bool
- WatchedEntry::EntryRemoved(ino_t node)
- {
- if (!fIsDirectory)
- return false;
- WatchedEntry *child = fEntries;
- WatchedEntry *lastChild = NULL;
- while (child) {
- if (child->fNode.node == node) {
- if (lastChild)
- lastChild->fLink = child->fLink;
- else
- fEntries = child->fLink;
- delete child;
- return true;
- }
- if (child->EntryRemoved(node))
- return true;
- lastChild = child;
- child = child->fLink;
- }
- return false;
- }
- bool
- WatchedEntry::InitCheck()
- {
- return fInitCheck;
- }
- RosterLooper::RosterLooper(USBRoster *roster)
- : BLooper("LibusbRoster Looper"),
- fRoster(roster),
- fRoot(NULL),
- fMessenger(NULL),
- fInitCheck(false)
- {
- BEntry entry("/dev/bus/usb");
- if (!entry.Exists()) {
- usbi_err(NULL, "usb_raw not published");
- return;
- }
- Run();
- fMessenger = new(std::nothrow) BMessenger(this);
- if (fMessenger == NULL) {
- usbi_err(NULL, "error creating BMessenger object");
- return;
- }
- if (Lock()) {
- entry_ref ref;
- entry.GetRef(&ref);
- fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
- Unlock();
- if (fRoot == NULL)
- return;
- if (fRoot->InitCheck() == false) {
- delete fRoot;
- fRoot = NULL;
- return;
- }
- }
- fInitCheck = true;
- }
- void
- RosterLooper::Stop()
- {
- Lock();
- delete fRoot;
- delete fMessenger;
- Quit();
- }
- void
- RosterLooper::MessageReceived(BMessage *message)
- {
- int32 opcode;
- if (message->FindInt32("opcode", &opcode) < B_OK)
- return;
- switch (opcode) {
- case B_ENTRY_CREATED:
- {
- dev_t device;
- ino_t directory;
- const char *name;
- if (message->FindInt32("device", &device) < B_OK ||
- message->FindInt64("directory", &directory) < B_OK ||
- message->FindString("name", &name) < B_OK)
- break;
- entry_ref ref(device, directory, name);
- fRoot->EntryCreated(&ref);
- break;
- }
- case B_ENTRY_REMOVED:
- {
- ino_t node;
- if (message->FindInt64("node", &node) < B_OK)
- break;
- fRoot->EntryRemoved(node);
- break;
- }
- }
- }
- bool
- RosterLooper::InitCheck()
- {
- return fInitCheck;
- }
- USBRoster::USBRoster()
- : fLooper(NULL)
- {
- }
- USBRoster::~USBRoster()
- {
- Stop();
- }
- int
- USBRoster::Start()
- {
- if (fLooper == NULL) {
- fLooper = new(std::nothrow) RosterLooper(this);
- if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) {
- if (fLooper)
- fLooper = NULL;
- return LIBUSB_ERROR_OTHER;
- }
- }
- return LIBUSB_SUCCESS;
- }
- void
- USBRoster::Stop()
- {
- if (fLooper) {
- ((RosterLooper *)fLooper)->Stop();
- fLooper = NULL;
- }
- }
|