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