xref: /haiku/src/kits/device/USBRoster.cpp (revision 97901ec593ec4dd50ac115c1c35a6d72f6e489a5)
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 	:	fRoster(roster),
187 		fRoot(NULL),
188 		fMessenger(NULL)
189 {
190 	BEntry entry("/dev/bus/usb");
191 	if (!entry.Exists()) {
192 		fprintf(stderr, "USBKit: usb_raw not published\n");
193 		return;
194 	}
195 
196 	Run();
197 	fMessenger = new(std::nothrow) BMessenger(this);
198 	if (fMessenger == NULL)
199 		return;
200 
201 	if (Lock()) {
202 		entry_ref ref;
203 		entry.GetRef(&ref);
204 		fRoot = new(std::nothrow) WatchedEntry(fRoster, fMessenger, &ref);
205 		Unlock();
206 	}
207 }
208 
209 
210 void
211 RosterLooper::Stop()
212 {
213 	Lock();
214 	delete fRoot;
215 	Quit();
216 }
217 
218 
219 void
220 RosterLooper::MessageReceived(BMessage *message)
221 {
222 	int32 opcode;
223 	if (message->FindInt32("opcode", &opcode) < B_OK)
224 		return;
225 
226 	switch (opcode) {
227 		case B_ENTRY_CREATED: {
228 			dev_t device;
229 			ino_t directory;
230 			const char *name;
231 			if (message->FindInt32("device", &device) < B_OK
232 				|| message->FindInt64("directory", &directory) < B_OK
233 				|| message->FindString("name", &name) < B_OK)
234 				break;
235 
236 			entry_ref ref(device, directory, name);
237 			fRoot->EntryCreated(&ref);
238 			break;
239 		}
240 
241 		case B_ENTRY_REMOVED: {
242 			ino_t node;
243 			if (message->FindInt64("node", &node) < B_OK)
244 				break;
245 
246 			fRoot->EntryRemoved(node);
247 			break;
248 		}
249 	}
250 }
251 
252 
253 BUSBRoster::BUSBRoster()
254 	:	fLooper(NULL)
255 {
256 }
257 
258 
259 BUSBRoster::~BUSBRoster()
260 {
261 	Stop();
262 }
263 
264 
265 void
266 BUSBRoster::Start()
267 {
268 	if (fLooper)
269 		return;
270 
271 	fLooper = new(std::nothrow) RosterLooper(this);
272 }
273 
274 
275 void
276 BUSBRoster::Stop()
277 {
278 	if (!fLooper)
279 		return;
280 
281 	((RosterLooper *)fLooper)->Stop();
282 	fLooper = NULL;
283 }
284 
285 
286 // definition of reserved virtual functions
287 void BUSBRoster::_ReservedUSBRoster1() {};
288 void BUSBRoster::_ReservedUSBRoster2() {};
289 void BUSBRoster::_ReservedUSBRoster3() {};
290 void BUSBRoster::_ReservedUSBRoster4() {};
291 void BUSBRoster::_ReservedUSBRoster5() {};
292