xref: /haiku/src/kits/device/USBRoster.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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 }
123 
124 
125 bool
126 WatchedEntry::EntryCreated(entry_ref *ref)
127 {
128 	if (!fIsDirectory)
129 		return false;
130 
131 	if (ref->directory != fNode.node) {
132 		WatchedEntry *child = fEntries;
133 		while (child) {
134 			if (child->EntryCreated(ref))
135 				return true;
136 			child = child->fLink;
137 		}
138 
139 		return false;
140 	}
141 
142 	WatchedEntry *child = new(std::nothrow) WatchedEntry(fRoster, fMessenger,
143 		ref);
144 	if (child == NULL)
145 		return false;
146 
147 	child->fLink = fEntries;
148 	fEntries = child;
149 	return true;
150 }
151 
152 
153 bool
154 WatchedEntry::EntryRemoved(ino_t node)
155 {
156 	if (!fIsDirectory)
157 		return false;
158 
159 	WatchedEntry *child = fEntries;
160 	WatchedEntry *lastChild = NULL;
161 	while (child) {
162 		if (child->fNode.node == node) {
163 			if (lastChild)
164 				lastChild->fLink = child->fLink;
165 			else
166 				fEntries = child->fLink;
167 
168 			delete child;
169 			return true;
170 		}
171 
172 		if (child->EntryRemoved(node))
173 			return true;
174 
175 		lastChild = child;
176 		child = child->fLink;
177 	}
178 
179 	return false;
180 }
181 
182 
183 RosterLooper::RosterLooper(BUSBRoster *roster)
184 	:	fRoster(roster),
185 		fRoot(NULL),
186 		fMessenger(NULL)
187 {
188 	BEntry entry("/dev/bus/usb");
189 	if (!entry.Exists()) {
190 		fprintf(stderr, "USBKit: usb_raw not published");
191 		return;
192 	}
193 
194 	Run();
195 	fMessenger = new(std::nothrow) BMessenger(this);
196 	if (fMessenger == NULL)
197 		return;
198 
199 	if (Lock()) {
200 		entry_ref ref;
201 		entry.GetRef(&ref);
202 		fRoot = new(std::nothrow) WatchedEntry(fRoster, fMessenger, &ref);
203 		Unlock();
204 	}
205 }
206 
207 
208 void
209 RosterLooper::Stop()
210 {
211 	Lock();
212 	delete fRoot;
213 	Quit();
214 }
215 
216 
217 void
218 RosterLooper::MessageReceived(BMessage *message)
219 {
220 	int32 opcode;
221 	if (message->FindInt32("opcode", &opcode) < B_OK)
222 		return;
223 
224 	switch (opcode) {
225 		case B_ENTRY_CREATED: {
226 			dev_t device;
227 			ino_t directory;
228 			const char *name;
229 			if (message->FindInt32("device", &device) < B_OK
230 				|| message->FindInt64("directory", &directory) < B_OK
231 				|| message->FindString("name", &name) < B_OK)
232 				break;
233 
234 			entry_ref ref(device, directory, name);
235 			fRoot->EntryCreated(&ref);
236 			break;
237 		}
238 
239 		case B_ENTRY_REMOVED: {
240 			ino_t node;
241 			if (message->FindInt64("node", &node) < B_OK)
242 				break;
243 
244 			fRoot->EntryRemoved(node);
245 			break;
246 		}
247 	}
248 }
249 
250 
251 BUSBRoster::BUSBRoster()
252 	:	fLooper(NULL)
253 {
254 }
255 
256 
257 BUSBRoster::~BUSBRoster()
258 {
259 	Stop();
260 }
261 
262 
263 void
264 BUSBRoster::Start()
265 {
266 	if (fLooper)
267 		return;
268 
269 	fLooper = new(std::nothrow) RosterLooper(this);
270 }
271 
272 
273 void
274 BUSBRoster::Stop()
275 {
276 	if (!fLooper)
277 		return;
278 
279 	((RosterLooper *)fLooper)->Stop();
280 	fLooper = NULL;
281 }
282 
283 
284 // definition of reserved virtual functions
285 void BUSBRoster::_ReservedUSBRoster1() {};
286 void BUSBRoster::_ReservedUSBRoster2() {};
287 void BUSBRoster::_ReservedUSBRoster3() {};
288 void BUSBRoster::_ReservedUSBRoster4() {};
289 void BUSBRoster::_ReservedUSBRoster5() {};
290