Fix issue 1) not recognizes some usb device, 2) reconnect when ffmpeg encoder error
[rtmpclient.git] / app / src / main / jni / libusb-1.0.22 / libusb / os / haiku_pollfs.cpp
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 "haiku_usb.h"
10 #include <cstdio>
11 #include <Directory.h>
12 #include <Entry.h>
13 #include <Looper.h>
14 #include <Messenger.h>
15 #include <Node.h>
16 #include <NodeMonitor.h>
17 #include <Path.h>
18 #include <cstring>
19
20 class WatchedEntry {
21 public:
22                         WatchedEntry(BMessenger *, entry_ref *);
23                         ~WatchedEntry();
24         bool            EntryCreated(entry_ref *ref);
25         bool            EntryRemoved(ino_t node);
26         bool            InitCheck();
27
28 private:
29         BMessenger*     fMessenger;
30         node_ref        fNode;
31         bool            fIsDirectory;
32         USBDevice*      fDevice;
33         WatchedEntry*   fEntries;
34         WatchedEntry*   fLink;
35         bool            fInitCheck;
36 };
37
38
39 class RosterLooper : public BLooper {
40 public:
41                         RosterLooper(USBRoster *);
42         void            Stop();
43         virtual void    MessageReceived(BMessage *);
44         bool            InitCheck();
45
46 private:
47         USBRoster*      fRoster;
48         WatchedEntry*   fRoot;
49         BMessenger*     fMessenger;
50         bool            fInitCheck;
51 };
52
53
54 WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
55         :       fMessenger(messenger),
56                 fIsDirectory(false),
57                 fDevice(NULL),
58                 fEntries(NULL),
59                 fLink(NULL),
60                 fInitCheck(false)
61 {
62         BEntry entry(ref);
63         entry.GetNodeRef(&fNode);
64
65         BDirectory directory;
66         if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
67                 fIsDirectory = true;
68
69                 while (directory.GetNextEntry(&entry) >= B_OK) {
70                         if (entry.GetRef(ref) < B_OK)
71                                 continue;
72
73                         WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
74                         if (child == NULL)
75                                 continue;
76                         if (child->InitCheck() == false) {
77                                 delete child;
78                                 continue;
79                         }
80
81                         child->fLink = fEntries;
82                         fEntries = child;
83                 }
84
85                 watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
86         }
87         else {
88                 if (strncmp(ref->name, "raw", 3) == 0)
89                         return;
90
91                 BPath path, parent_path;
92                 entry.GetPath(&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;
98
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);
102                                 if (dev) {
103                                         usbi_dbg("using previously allocated device with location %lu", session_id);
104                                         libusb_unref_device(dev);
105                                         continue;
106                                 }
107                                 usbi_dbg("allocating new device with location %lu", session_id);
108                                 dev = usbi_alloc_device(ctx, session_id);
109                                 if (!dev) {
110                                         usbi_dbg("device allocation failed");
111                                         continue;
112                                 }
113                                 *((USBDevice **)dev->os_priv) = fDevice;
114
115                                 // Calculate pseudo-device-address
116                                 int addr, tmp;
117                                 if (strcmp(path.Leaf(), "hub") == 0)
118                                         tmp = 100;      //Random Number
119                                 else
120                                         sscanf(path.Leaf(), "%d", &tmp);
121                                 addr = tmp + 1;
122                                 path.GetParent(&parent_path);
123                                 while (strcmp(parent_path.Leaf(), "usb") != 0) {
124                                         sscanf(parent_path.Leaf(), "%d", &tmp);
125                                         addr += tmp + 1;
126                                         parent_path.GetParent(&parent_path);
127                                 }
128                                 sscanf(path.Path(), "/dev/bus/usb/%d", &dev->bus_number);
129                                 dev->device_address = addr - (dev->bus_number + 1);
130
131                                 if (usbi_sanitize_device(dev) < 0) {
132                                         usbi_dbg("device sanitization failed");
133                                         libusb_unref_device(dev);
134                                         continue;
135                                 }
136                                 usbi_connect_device(dev);
137                         }
138                         usbi_mutex_unlock(&active_contexts_lock);
139                 }
140                 else if (fDevice) {
141                         delete fDevice;
142                         fDevice = NULL;
143                         return;
144                 }
145         }
146         fInitCheck = true;
147 }
148
149
150 WatchedEntry::~WatchedEntry()
151 {
152         if (fIsDirectory) {
153                 watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
154
155                 WatchedEntry *child = fEntries;
156                 while (child) {
157                         WatchedEntry *next = child->fLink;
158                         delete child;
159                         child = next;
160                 }
161         }
162
163         if (fDevice) {
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;
168
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);
172                         if (dev != NULL) {
173                                 usbi_disconnect_device(dev);
174                                 libusb_unref_device(dev);
175                         } else {
176                                 usbi_dbg("device with location %lu not found", session_id);
177                         }
178                 }
179                 usbi_mutex_static_unlock(&active_contexts_lock);
180                 delete fDevice;
181         }
182 }
183
184
185 bool
186 WatchedEntry::EntryCreated(entry_ref *ref)
187 {
188         if (!fIsDirectory)
189                 return false;
190
191         if (ref->directory != fNode.node) {
192                 WatchedEntry *child = fEntries;
193                 while (child) {
194                         if (child->EntryCreated(ref))
195                                 return true;
196                         child = child->fLink;
197                 }
198                 return false;
199         }
200
201         WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
202         if (child == NULL)
203                 return false;
204         child->fLink = fEntries;
205         fEntries = child;
206         return true;
207 }
208
209
210 bool
211 WatchedEntry::EntryRemoved(ino_t node)
212 {
213         if (!fIsDirectory)
214                 return false;
215
216         WatchedEntry *child = fEntries;
217         WatchedEntry *lastChild = NULL;
218         while (child) {
219                 if (child->fNode.node == node) {
220                         if (lastChild)
221                                 lastChild->fLink = child->fLink;
222                         else
223                                 fEntries = child->fLink;
224                         delete child;
225                         return true;
226                 }
227
228                 if (child->EntryRemoved(node))
229                         return true;
230
231                 lastChild = child;
232                 child = child->fLink;
233         }
234         return false;
235 }
236
237
238 bool
239 WatchedEntry::InitCheck()
240 {
241         return fInitCheck;
242 }
243
244
245 RosterLooper::RosterLooper(USBRoster *roster)
246         :       BLooper("LibusbRoster Looper"),
247                 fRoster(roster),
248                 fRoot(NULL),
249                 fMessenger(NULL),
250                 fInitCheck(false)
251 {
252         BEntry entry("/dev/bus/usb");
253         if (!entry.Exists()) {
254                 usbi_err(NULL, "usb_raw not published");
255                 return;
256         }
257
258         Run();
259         fMessenger = new(std::nothrow) BMessenger(this);
260         if (fMessenger == NULL) {
261                 usbi_err(NULL, "error creating BMessenger object");
262                 return;
263         }
264
265         if (Lock()) {
266                 entry_ref ref;
267                 entry.GetRef(&ref);
268                 fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
269                 Unlock();
270                 if (fRoot == NULL)
271                         return;
272                 if (fRoot->InitCheck() == false) {
273                         delete fRoot;
274                         fRoot = NULL;
275                         return;
276                 }
277         }
278         fInitCheck = true;
279 }
280
281
282 void
283 RosterLooper::Stop()
284 {
285         Lock();
286         delete fRoot;
287         delete fMessenger;
288         Quit();
289 }
290
291
292 void
293 RosterLooper::MessageReceived(BMessage *message)
294 {
295         int32 opcode;
296         if (message->FindInt32("opcode", &opcode) < B_OK)
297                 return;
298
299         switch (opcode) {
300                 case B_ENTRY_CREATED:
301                 {
302                         dev_t device;
303                         ino_t directory;
304                         const char *name;
305                         if (message->FindInt32("device", &device) < B_OK ||
306                                 message->FindInt64("directory", &directory) < B_OK ||
307                                 message->FindString("name", &name) < B_OK)
308                                 break;
309
310                         entry_ref ref(device, directory, name);
311                         fRoot->EntryCreated(&ref);
312                         break;
313                 }
314                 case B_ENTRY_REMOVED:
315                 {
316                         ino_t node;
317                         if (message->FindInt64("node", &node) < B_OK)
318                                 break;
319                         fRoot->EntryRemoved(node);
320                         break;
321                 }
322         }
323 }
324
325
326 bool
327 RosterLooper::InitCheck()
328 {
329         return fInitCheck;
330 }
331
332
333 USBRoster::USBRoster()
334         :       fLooper(NULL)
335 {
336 }
337
338
339 USBRoster::~USBRoster()
340 {
341         Stop();
342 }
343
344
345 int
346 USBRoster::Start()
347 {
348         if (fLooper == NULL) {
349                 fLooper = new(std::nothrow) RosterLooper(this);
350                 if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) {
351                         if (fLooper)
352                                 fLooper = NULL;
353                         return LIBUSB_ERROR_OTHER;
354                 }
355         }
356         return LIBUSB_SUCCESS;
357 }
358
359
360 void
361 USBRoster::Stop()
362 {
363         if (fLooper) {
364                 ((RosterLooper *)fLooper)->Stop();
365                 fLooper = NULL;
366         }
367 }