2 * Copyright 2007-2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Lotz <mmlr@mlotz.ch>
11 #include <Directory.h>
14 #include <Messenger.h>
16 #include <NodeMonitor.h>
22 WatchedEntry(BMessenger *, entry_ref *);
24 bool EntryCreated(entry_ref *ref);
25 bool EntryRemoved(ino_t node);
29 BMessenger* fMessenger;
33 WatchedEntry* fEntries;
39 class RosterLooper : public BLooper {
41 RosterLooper(USBRoster *);
43 virtual void MessageReceived(BMessage *);
49 BMessenger* fMessenger;
54 WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
55 : fMessenger(messenger),
63 entry.GetNodeRef(&fNode);
66 if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
69 while (directory.GetNextEntry(&entry) >= B_OK) {
70 if (entry.GetRef(ref) < B_OK)
73 WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
76 if (child->InitCheck() == false) {
81 child->fLink = fEntries;
85 watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
88 if (strncmp(ref->name, "raw", 3) == 0)
91 BPath path, parent_path;
93 fDevice = new(std::nothrow) USBDevice(path.Path());
94 if (fDevice != NULL && fDevice->InitCheck() == true) {
95 // Add this new device to each active context's device list
96 struct libusb_context *ctx;
97 unsigned long session_id = (unsigned long)&fDevice;
99 usbi_mutex_lock(&active_contexts_lock);
100 list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
101 struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
103 usbi_dbg("using previously allocated device with location %lu", session_id);
104 libusb_unref_device(dev);
107 usbi_dbg("allocating new device with location %lu", session_id);
108 dev = usbi_alloc_device(ctx, session_id);
110 usbi_dbg("device allocation failed");
113 *((USBDevice **)dev->os_priv) = fDevice;
115 // Calculate pseudo-device-address
117 if (strcmp(path.Leaf(), "hub") == 0)
118 tmp = 100; //Random Number
120 sscanf(path.Leaf(), "%d", &tmp);
122 path.GetParent(&parent_path);
123 while (strcmp(parent_path.Leaf(), "usb") != 0) {
124 sscanf(parent_path.Leaf(), "%d", &tmp);
126 parent_path.GetParent(&parent_path);
128 sscanf(path.Path(), "/dev/bus/usb/%d", &dev->bus_number);
129 dev->device_address = addr - (dev->bus_number + 1);
131 if (usbi_sanitize_device(dev) < 0) {
132 usbi_dbg("device sanitization failed");
133 libusb_unref_device(dev);
136 usbi_connect_device(dev);
138 usbi_mutex_unlock(&active_contexts_lock);
150 WatchedEntry::~WatchedEntry()
153 watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
155 WatchedEntry *child = fEntries;
157 WatchedEntry *next = child->fLink;
164 // Remove this device from each active context's device list
165 struct libusb_context *ctx;
166 struct libusb_device *dev;
167 unsigned long session_id = (unsigned long)&fDevice;
169 usbi_mutex_lock(&active_contexts_lock);
170 list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
171 dev = usbi_get_device_by_session_id(ctx, session_id);
173 usbi_disconnect_device(dev);
174 libusb_unref_device(dev);
176 usbi_dbg("device with location %lu not found", session_id);
179 usbi_mutex_static_unlock(&active_contexts_lock);
186 WatchedEntry::EntryCreated(entry_ref *ref)
191 if (ref->directory != fNode.node) {
192 WatchedEntry *child = fEntries;
194 if (child->EntryCreated(ref))
196 child = child->fLink;
201 WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
204 child->fLink = fEntries;
211 WatchedEntry::EntryRemoved(ino_t node)
216 WatchedEntry *child = fEntries;
217 WatchedEntry *lastChild = NULL;
219 if (child->fNode.node == node) {
221 lastChild->fLink = child->fLink;
223 fEntries = child->fLink;
228 if (child->EntryRemoved(node))
232 child = child->fLink;
239 WatchedEntry::InitCheck()
245 RosterLooper::RosterLooper(USBRoster *roster)
246 : BLooper("LibusbRoster Looper"),
252 BEntry entry("/dev/bus/usb");
253 if (!entry.Exists()) {
254 usbi_err(NULL, "usb_raw not published");
259 fMessenger = new(std::nothrow) BMessenger(this);
260 if (fMessenger == NULL) {
261 usbi_err(NULL, "error creating BMessenger object");
268 fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
272 if (fRoot->InitCheck() == false) {
293 RosterLooper::MessageReceived(BMessage *message)
296 if (message->FindInt32("opcode", &opcode) < B_OK)
300 case B_ENTRY_CREATED:
305 if (message->FindInt32("device", &device) < B_OK ||
306 message->FindInt64("directory", &directory) < B_OK ||
307 message->FindString("name", &name) < B_OK)
310 entry_ref ref(device, directory, name);
311 fRoot->EntryCreated(&ref);
314 case B_ENTRY_REMOVED:
317 if (message->FindInt64("node", &node) < B_OK)
319 fRoot->EntryRemoved(node);
327 RosterLooper::InitCheck()
333 USBRoster::USBRoster()
339 USBRoster::~USBRoster()
348 if (fLooper == NULL) {
349 fLooper = new(std::nothrow) RosterLooper(this);
350 if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) {
353 return LIBUSB_ERROR_OTHER;
356 return LIBUSB_SUCCESS;
364 ((RosterLooper *)fLooper)->Stop();