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