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