Files
haiku-beta6/src/libs/usb/USBRoster.cpp
T
Michael Lotz 3c0b8e7fff Commiting reimplemented USBKit that is compatible with the old Be sample code version.
It is supposed to be cleaner and more object oriented. It also adds some features (like a string getter for the interface) that were appearantly left out in the Be implementation.
It is currently built as a small static library from src/libs.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19913 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-01-23 15:55:34 +00:00

270 lines
4.4 KiB
C++

/*
* Copyright 2007, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <[email protected]>
*/
#include <USBKit.h>
#include <usb_raw.h>
#include <Directory.h>
#include <Entry.h>
#include <Looper.h>
#include <Messenger.h>
#include <Node.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <stdio.h>
#include <string.h>
class WatchedEntry {
public:
WatchedEntry(BUSBRoster *roster,
BMessenger *messenger, entry_ref *ref);
~WatchedEntry();
bool EntryCreated(entry_ref *ref);
bool EntryRemoved(ino_t node);
private:
BUSBRoster *fRoster;
BMessenger *fMessenger;
node_ref fNode;
bool fIsDirectory;
BUSBDevice *fDevice;
WatchedEntry *fEntries;
WatchedEntry *fLink;
};
class RosterLooper : public BLooper {
public:
RosterLooper(BUSBRoster *roster);
void Stop();
virtual void MessageReceived(BMessage *message);
private:
BUSBRoster *fRoster;
WatchedEntry *fRoot;
BMessenger *fMessenger;
};
WatchedEntry::WatchedEntry(BUSBRoster *roster, BMessenger *messenger,
entry_ref *ref)
: fRoster(roster),
fMessenger(messenger),
fIsDirectory(false),
fDevice(NULL),
fEntries(NULL),
fLink(NULL)
{
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 WatchedEntry(fRoster, fMessenger, ref);
child->fLink = fEntries;
fEntries = child;
}
watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
} else {
// filter pseudoentry that only handles ioctls
if (strncmp(ref->name, "raw", 3) == 0)
return;
BPath path;
entry.GetPath(&path);
fDevice = new BUSBDevice(path.Path());
if (fRoster->DeviceAdded(fDevice) != B_OK) {
delete fDevice;
fDevice = NULL;
}
}
}
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)
fRoster->DeviceRemoved(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 WatchedEntry(fRoster, fMessenger, ref);
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;
}
RosterLooper::RosterLooper(BUSBRoster *roster)
: fRoster(roster),
fRoot(NULL),
fMessenger(NULL)
{
BEntry entry("/dev/bus/usb");
if (!entry.Exists()) {
fprintf(stderr, "USBKit: usb_raw not published");
return;
}
Run();
fMessenger = new BMessenger(this);
if (Lock()) {
entry_ref ref;
entry.GetRef(&ref);
fRoot = new WatchedEntry(fRoster, fMessenger, &ref);
Unlock();
}
}
void
RosterLooper::Stop()
{
Lock();
delete fRoot;
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;
}
}
}
BUSBRoster::BUSBRoster()
: fLooper(NULL)
{
}
BUSBRoster::~BUSBRoster()
{
Stop();
}
void
BUSBRoster::Start()
{
if (fLooper)
return;
fLooper = new RosterLooper(this);
}
void
BUSBRoster::Stop()
{
if (!fLooper)
return;
((RosterLooper *)fLooper)->Stop();
fLooper = NULL;
}