xref: /haiku/src/kits/device/USBRoster.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
1 /*
2  * Copyright 2007-2008, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include <USBKit.h>
10 #include <Directory.h>
11 #include <Entry.h>
12 #include <Looper.h>
13 #include <Messenger.h>
14 #include <Node.h>
15 #include <NodeMonitor.h>
16 #include <Path.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <new>
20 
21 
22 class WatchedEntry {
23 public:
24 							WatchedEntry(BUSBRoster *roster,
25 								BMessenger *messenger, entry_ref *ref);
26 							~WatchedEntry();
27 
28 		bool				EntryCreated(entry_ref *ref);
29 		bool				EntryRemoved(ino_t node);
30 
31 private:
32 		BUSBRoster *		fRoster;
33 		BMessenger *		fMessenger;
34 
35 		node_ref			fNode;
36 		bool				fIsDirectory;
37 		BUSBDevice *		fDevice;
38 
39 		WatchedEntry *		fEntries;
40 		WatchedEntry *		fLink;
41 };
42 
43 
44 class RosterLooper : public BLooper {
45 public:
46 							RosterLooper(BUSBRoster *roster);
47 
48 		void				Stop();
49 
50 virtual	void				MessageReceived(BMessage *message);
51 
52 private:
53 		BUSBRoster *		fRoster;
54 		WatchedEntry *		fRoot;
55 		BMessenger *		fMessenger;
56 };
57 
58 
59 WatchedEntry::WatchedEntry(BUSBRoster *roster, BMessenger *messenger,
60 	entry_ref *ref)
61 	:	fRoster(roster),
62 		fMessenger(messenger),
63 		fIsDirectory(false),
64 		fDevice(NULL),
65 		fEntries(NULL),
66 		fLink(NULL)
67 {
68 	BEntry entry(ref);
69 	entry.GetNodeRef(&fNode);
70 
71 	BDirectory directory;
72 	if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
73 		fIsDirectory = true;
74 
75 		while(directory.GetNextEntry(&entry) >= B_OK) {
76 			if (entry.GetRef(ref) < B_OK)
77 				continue;
78 
79 			WatchedEntry *child = new(std::nothrow) WatchedEntry(fRoster,
80 				fMessenger, ref);
81 			if (child == NULL)
82 				continue;
83 
84 			child->fLink = fEntries;
85 			fEntries = child;
86 		}
87 
88 		watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
89 	} else {
90 		// filter pseudoentry that only handles ioctls
91 		if (strncmp(ref->name, "raw", 3) == 0)
92 			return;
93 
94 		BPath path;
95 		entry.GetPath(&path);
96 		fDevice = new(std::nothrow) BUSBDevice(path.Path());
97 		if (fDevice != NULL) {
98 			if (fRoster->DeviceAdded(fDevice) != B_OK) {
99 				delete fDevice;
100 				fDevice = NULL;
101 			}
102 		}
103 	}
104 }
105 
106 
107 WatchedEntry::~WatchedEntry()
108 {
109 	if (fIsDirectory) {
110 		watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
111 
112 		WatchedEntry *child = fEntries;
113 		while (child) {
114 			WatchedEntry *next = child->fLink;
115 			delete child;
116 			child = next;
117 		}
118 	}
119 
120 	if (fDevice) {
121 		fRoster->DeviceRemoved(fDevice);
122 		delete fDevice;
123 	}
124 }
125 
126 
127 bool
128 WatchedEntry::EntryCreated(entry_ref *ref)
129 {
130 	if (!fIsDirectory)
131 		return false;
132 
133 	if (ref->directory != fNode.node) {
134 		WatchedEntry *child = fEntries;
135 		while (child) {
136 			if (child->EntryCreated(ref))
137 				return true;
138 			child = child->fLink;
139 		}
140 
141 		return false;
142 	}
143 
144 	WatchedEntry *child = new(std::nothrow) WatchedEntry(fRoster, fMessenger,
145 		ref);
146 	if (child == NULL)
147 		return false;
148 
149 	child->fLink = fEntries;
150 	fEntries = child;
151 	return true;
152 }
153 
154 
155 bool
156 WatchedEntry::EntryRemoved(ino_t node)
157 {
158 	if (!fIsDirectory)
159 		return false;
160 
161 	WatchedEntry *child = fEntries;
162 	WatchedEntry *lastChild = NULL;
163 	while (child) {
164 		if (child->fNode.node == node) {
165 			if (lastChild)
166 				lastChild->fLink = child->fLink;
167 			else
168 				fEntries = child->fLink;
169 
170 			delete child;
171 			return true;
172 		}
173 
174 		if (child->EntryRemoved(node))
175 			return true;
176 
177 		lastChild = child;
178 		child = child->fLink;
179 	}
180 
181 	return false;
182 }
183 
184 
185 RosterLooper::RosterLooper(BUSBRoster *roster)
186 	:	BLooper("BUSBRoster looper"),
187 		fRoster(roster),
188 		fRoot(NULL),
189 		fMessenger(NULL)
190 {
191 	BEntry entry("/dev/bus/usb");
192 	if (!entry.Exists()) {
193 		fprintf(stderr, "USBKit: usb_raw not published\n");
194 		return;
195 	}
196 
197 	Run();
198 	fMessenger = new(std::nothrow) BMessenger(this);
199 	if (fMessenger == NULL)
200 		return;
201 
202 	if (Lock()) {
203 		entry_ref ref;
204 		entry.GetRef(&ref);
205 		fRoot = new(std::nothrow) WatchedEntry(fRoster, fMessenger, &ref);
206 		Unlock();
207 	}
208 }
209 
210 
211 void
212 RosterLooper::Stop()
213 {
214 	Lock();
215 	delete fRoot;
216 	Quit();
217 }
218 
219 
220 void
221 RosterLooper::MessageReceived(BMessage *message)
222 {
223 	int32 opcode;
224 	if (message->FindInt32("opcode", &opcode) < B_OK)
225 		return;
226 
227 	switch (opcode) {
228 		case B_ENTRY_CREATED: {
229 			dev_t device;
230 			ino_t directory;
231 			const char *name;
232 			if (message->FindInt32("device", &device) < B_OK
233 				|| message->FindInt64("directory", &directory) < B_OK
234 				|| message->FindString("name", &name) < B_OK)
235 				break;
236 
237 			entry_ref ref(device, directory, name);
238 			fRoot->EntryCreated(&ref);
239 			break;
240 		}
241 
242 		case B_ENTRY_REMOVED: {
243 			ino_t node;
244 			if (message->FindInt64("node", &node) < B_OK)
245 				break;
246 
247 			fRoot->EntryRemoved(node);
248 			break;
249 		}
250 	}
251 }
252 
253 
254 BUSBRoster::BUSBRoster()
255 	:	fLooper(NULL)
256 {
257 }
258 
259 
260 BUSBRoster::~BUSBRoster()
261 {
262 	Stop();
263 }
264 
265 
266 void
267 BUSBRoster::Start()
268 {
269 	if (fLooper)
270 		return;
271 
272 	fLooper = new(std::nothrow) RosterLooper(this);
273 }
274 
275 
276 void
277 BUSBRoster::Stop()
278 {
279 	if (!fLooper)
280 		return;
281 
282 	((RosterLooper *)fLooper)->Stop();
283 	fLooper = NULL;
284 }
285 
286 
287 // definition of reserved virtual functions
288 void BUSBRoster::_ReservedUSBRoster1() {};
289 void BUSBRoster::_ReservedUSBRoster2() {};
290 void BUSBRoster::_ReservedUSBRoster3() {};
291 void BUSBRoster::_ReservedUSBRoster4() {};
292 void BUSBRoster::_ReservedUSBRoster5() {};
293