haiku_pollfs.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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. #include "haiku_usb.h"
  9. #include <cstdio>
  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 <cstring>
  18. class WatchedEntry {
  19. public:
  20. WatchedEntry(BMessenger *, entry_ref *);
  21. ~WatchedEntry();
  22. bool EntryCreated(entry_ref *ref);
  23. bool EntryRemoved(ino_t node);
  24. bool InitCheck();
  25. private:
  26. BMessenger* fMessenger;
  27. node_ref fNode;
  28. bool fIsDirectory;
  29. USBDevice* fDevice;
  30. WatchedEntry* fEntries;
  31. WatchedEntry* fLink;
  32. bool fInitCheck;
  33. };
  34. class RosterLooper : public BLooper {
  35. public:
  36. RosterLooper(USBRoster *);
  37. void Stop();
  38. virtual void MessageReceived(BMessage *);
  39. bool InitCheck();
  40. private:
  41. USBRoster* fRoster;
  42. WatchedEntry* fRoot;
  43. BMessenger* fMessenger;
  44. bool fInitCheck;
  45. };
  46. WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
  47. : fMessenger(messenger),
  48. fIsDirectory(false),
  49. fDevice(NULL),
  50. fEntries(NULL),
  51. fLink(NULL),
  52. fInitCheck(false)
  53. {
  54. BEntry entry(ref);
  55. entry.GetNodeRef(&fNode);
  56. BDirectory directory;
  57. if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
  58. fIsDirectory = true;
  59. while (directory.GetNextEntry(&entry) >= B_OK) {
  60. if (entry.GetRef(ref) < B_OK)
  61. continue;
  62. WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
  63. if (child == NULL)
  64. continue;
  65. if (child->InitCheck() == false) {
  66. delete child;
  67. continue;
  68. }
  69. child->fLink = fEntries;
  70. fEntries = child;
  71. }
  72. watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
  73. }
  74. else {
  75. if (strncmp(ref->name, "raw", 3) == 0)
  76. return;
  77. BPath path, parent_path;
  78. entry.GetPath(&path);
  79. fDevice = new(std::nothrow) USBDevice(path.Path());
  80. if (fDevice != NULL && fDevice->InitCheck() == true) {
  81. // Add this new device to each active context's device list
  82. struct libusb_context *ctx;
  83. unsigned long session_id = (unsigned long)&fDevice;
  84. usbi_mutex_lock(&active_contexts_lock);
  85. for_each_context(ctx) {
  86. struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
  87. if (dev) {
  88. usbi_dbg(NULL, "using previously allocated device with location %lu", session_id);
  89. libusb_unref_device(dev);
  90. continue;
  91. }
  92. usbi_dbg(NULL, "allocating new device with location %lu", session_id);
  93. dev = usbi_alloc_device(ctx, session_id);
  94. if (!dev) {
  95. usbi_dbg(NULL, "device allocation failed");
  96. continue;
  97. }
  98. *((USBDevice **)usbi_get_device_priv(dev)) = fDevice;
  99. // Calculate pseudo-device-address
  100. int addr, tmp;
  101. if (strcmp(path.Leaf(), "hub") == 0)
  102. tmp = 100; //Random Number
  103. else
  104. sscanf(path.Leaf(), "%d", &tmp);
  105. addr = tmp + 1;
  106. path.GetParent(&parent_path);
  107. while (strcmp(parent_path.Leaf(), "usb") != 0) {
  108. sscanf(parent_path.Leaf(), "%d", &tmp);
  109. addr += tmp + 1;
  110. parent_path.GetParent(&parent_path);
  111. }
  112. sscanf(path.Path(), "/dev/bus/usb/%hhu", &dev->bus_number);
  113. dev->device_address = addr - (dev->bus_number + 1);
  114. static_assert(sizeof(dev->device_descriptor) == sizeof(usb_device_descriptor),
  115. "mismatch between libusb and OS device descriptor sizes");
  116. memcpy(&dev->device_descriptor, fDevice->Descriptor(), LIBUSB_DT_DEVICE_SIZE);
  117. usbi_localize_device_descriptor(&dev->device_descriptor);
  118. if (usbi_sanitize_device(dev) < 0) {
  119. usbi_dbg(NULL, "device sanitization failed");
  120. libusb_unref_device(dev);
  121. continue;
  122. }
  123. usbi_connect_device(dev);
  124. }
  125. usbi_mutex_unlock(&active_contexts_lock);
  126. }
  127. else if (fDevice) {
  128. delete fDevice;
  129. fDevice = NULL;
  130. return;
  131. }
  132. }
  133. fInitCheck = true;
  134. }
  135. WatchedEntry::~WatchedEntry()
  136. {
  137. if (fIsDirectory) {
  138. watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
  139. WatchedEntry *child = fEntries;
  140. while (child) {
  141. WatchedEntry *next = child->fLink;
  142. delete child;
  143. child = next;
  144. }
  145. }
  146. if (fDevice) {
  147. // Remove this device from each active context's device list
  148. struct libusb_context *ctx;
  149. struct libusb_device *dev;
  150. unsigned long session_id = (unsigned long)&fDevice;
  151. usbi_mutex_lock(&active_contexts_lock);
  152. for_each_context(ctx) {
  153. dev = usbi_get_device_by_session_id(ctx, session_id);
  154. if (dev != NULL) {
  155. usbi_disconnect_device(dev);
  156. libusb_unref_device(dev);
  157. } else {
  158. usbi_dbg(ctx, "device with location %lu not found", session_id);
  159. }
  160. }
  161. usbi_mutex_static_unlock(&active_contexts_lock);
  162. delete fDevice;
  163. }
  164. }
  165. bool
  166. WatchedEntry::EntryCreated(entry_ref *ref)
  167. {
  168. if (!fIsDirectory)
  169. return false;
  170. if (ref->directory != fNode.node) {
  171. WatchedEntry *child = fEntries;
  172. while (child) {
  173. if (child->EntryCreated(ref))
  174. return true;
  175. child = child->fLink;
  176. }
  177. return false;
  178. }
  179. WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
  180. if (child == NULL)
  181. return false;
  182. child->fLink = fEntries;
  183. fEntries = child;
  184. return true;
  185. }
  186. bool
  187. WatchedEntry::EntryRemoved(ino_t node)
  188. {
  189. if (!fIsDirectory)
  190. return false;
  191. WatchedEntry *child = fEntries;
  192. WatchedEntry *lastChild = NULL;
  193. while (child) {
  194. if (child->fNode.node == node) {
  195. if (lastChild)
  196. lastChild->fLink = child->fLink;
  197. else
  198. fEntries = child->fLink;
  199. delete child;
  200. return true;
  201. }
  202. if (child->EntryRemoved(node))
  203. return true;
  204. lastChild = child;
  205. child = child->fLink;
  206. }
  207. return false;
  208. }
  209. bool
  210. WatchedEntry::InitCheck()
  211. {
  212. return fInitCheck;
  213. }
  214. RosterLooper::RosterLooper(USBRoster *roster)
  215. : BLooper("LibusbRoster Looper"),
  216. fRoster(roster),
  217. fRoot(NULL),
  218. fMessenger(NULL),
  219. fInitCheck(false)
  220. {
  221. BEntry entry("/dev/bus/usb");
  222. if (!entry.Exists()) {
  223. usbi_err(NULL, "usb_raw not published");
  224. return;
  225. }
  226. Run();
  227. fMessenger = new(std::nothrow) BMessenger(this);
  228. if (fMessenger == NULL) {
  229. usbi_err(NULL, "error creating BMessenger object");
  230. return;
  231. }
  232. if (Lock()) {
  233. entry_ref ref;
  234. entry.GetRef(&ref);
  235. fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
  236. Unlock();
  237. if (fRoot == NULL)
  238. return;
  239. if (fRoot->InitCheck() == false) {
  240. delete fRoot;
  241. fRoot = NULL;
  242. return;
  243. }
  244. }
  245. fInitCheck = true;
  246. }
  247. void
  248. RosterLooper::Stop()
  249. {
  250. Lock();
  251. delete fRoot;
  252. delete fMessenger;
  253. Quit();
  254. }
  255. void
  256. RosterLooper::MessageReceived(BMessage *message)
  257. {
  258. int32 opcode;
  259. if (message->FindInt32("opcode", &opcode) < B_OK)
  260. return;
  261. switch (opcode) {
  262. case B_ENTRY_CREATED:
  263. {
  264. dev_t device;
  265. ino_t directory;
  266. const char *name;
  267. if (message->FindInt32("device", &device) < B_OK ||
  268. message->FindInt64("directory", &directory) < B_OK ||
  269. message->FindString("name", &name) < B_OK)
  270. break;
  271. entry_ref ref(device, directory, name);
  272. fRoot->EntryCreated(&ref);
  273. break;
  274. }
  275. case B_ENTRY_REMOVED:
  276. {
  277. ino_t node;
  278. if (message->FindInt64("node", &node) < B_OK)
  279. break;
  280. fRoot->EntryRemoved(node);
  281. break;
  282. }
  283. }
  284. }
  285. bool
  286. RosterLooper::InitCheck()
  287. {
  288. return fInitCheck;
  289. }
  290. USBRoster::USBRoster()
  291. : fLooper(NULL)
  292. {
  293. }
  294. USBRoster::~USBRoster()
  295. {
  296. Stop();
  297. }
  298. int
  299. USBRoster::Start()
  300. {
  301. if (fLooper == NULL) {
  302. fLooper = new(std::nothrow) RosterLooper(this);
  303. if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) {
  304. if (fLooper)
  305. fLooper = NULL;
  306. return LIBUSB_ERROR_OTHER;
  307. }
  308. }
  309. return LIBUSB_SUCCESS;
  310. }
  311. void
  312. USBRoster::Stop()
  313. {
  314. if (fLooper) {
  315. ((RosterLooper *)fLooper)->Stop();
  316. fLooper = NULL;
  317. }
  318. }