1 /* 2 * Copyright 2007, 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 20 21 class WatchedEntry { 22 public: 23 WatchedEntry(BUSBRoster *roster, 24 BMessenger *messenger, entry_ref *ref); 25 ~WatchedEntry(); 26 27 bool EntryCreated(entry_ref *ref); 28 bool EntryRemoved(ino_t node); 29 30 private: 31 BUSBRoster *fRoster; 32 BMessenger *fMessenger; 33 34 node_ref fNode; 35 bool fIsDirectory; 36 BUSBDevice *fDevice; 37 38 WatchedEntry *fEntries; 39 WatchedEntry *fLink; 40 }; 41 42 43 class RosterLooper : public BLooper { 44 public: 45 RosterLooper(BUSBRoster *roster); 46 47 void Stop(); 48 49 virtual void MessageReceived(BMessage *message); 50 51 private: 52 BUSBRoster *fRoster; 53 WatchedEntry *fRoot; 54 BMessenger *fMessenger; 55 }; 56 57 58 WatchedEntry::WatchedEntry(BUSBRoster *roster, BMessenger *messenger, 59 entry_ref *ref) 60 : fRoster(roster), 61 fMessenger(messenger), 62 fIsDirectory(false), 63 fDevice(NULL), 64 fEntries(NULL), 65 fLink(NULL) 66 { 67 BEntry entry(ref); 68 entry.GetNodeRef(&fNode); 69 70 BDirectory directory; 71 if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) { 72 fIsDirectory = true; 73 74 while(directory.GetNextEntry(&entry) >= B_OK) { 75 if (entry.GetRef(ref) < B_OK) 76 continue; 77 78 WatchedEntry *child = new WatchedEntry(fRoster, fMessenger, ref); 79 child->fLink = fEntries; 80 fEntries = child; 81 } 82 83 watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger); 84 } else { 85 // filter pseudoentry that only handles ioctls 86 if (strncmp(ref->name, "raw", 3) == 0) 87 return; 88 89 BPath path; 90 entry.GetPath(&path); 91 fDevice = new BUSBDevice(path.Path()); 92 if (fRoster->DeviceAdded(fDevice) != B_OK) { 93 delete fDevice; 94 fDevice = NULL; 95 } 96 } 97 } 98 99 100 WatchedEntry::~WatchedEntry() 101 { 102 if (fIsDirectory) { 103 watch_node(&fNode, B_STOP_WATCHING, *fMessenger); 104 105 WatchedEntry *child = fEntries; 106 while (child) { 107 WatchedEntry *next = child->fLink; 108 delete child; 109 child = next; 110 } 111 } 112 113 if (fDevice) 114 fRoster->DeviceRemoved(fDevice); 115 } 116 117 118 bool 119 WatchedEntry::EntryCreated(entry_ref *ref) 120 { 121 if (!fIsDirectory) 122 return false; 123 124 if (ref->directory != fNode.node) { 125 WatchedEntry *child = fEntries; 126 while (child) { 127 if (child->EntryCreated(ref)) 128 return true; 129 child = child->fLink; 130 } 131 132 return false; 133 } 134 135 WatchedEntry *child = new WatchedEntry(fRoster, fMessenger, ref); 136 child->fLink = fEntries; 137 fEntries = child; 138 return true; 139 } 140 141 142 bool 143 WatchedEntry::EntryRemoved(ino_t node) 144 { 145 if (!fIsDirectory) 146 return false; 147 148 WatchedEntry *child = fEntries; 149 WatchedEntry *lastChild = NULL; 150 while (child) { 151 if (child->fNode.node == node) { 152 if (lastChild) 153 lastChild->fLink = child->fLink; 154 else 155 fEntries = child->fLink; 156 157 delete child; 158 return true; 159 } 160 161 if (child->EntryRemoved(node)) 162 return true; 163 164 lastChild = child; 165 child = child->fLink; 166 } 167 168 return false; 169 } 170 171 172 RosterLooper::RosterLooper(BUSBRoster *roster) 173 : fRoster(roster), 174 fRoot(NULL), 175 fMessenger(NULL) 176 { 177 BEntry entry("/dev/bus/usb"); 178 if (!entry.Exists()) { 179 fprintf(stderr, "USBKit: usb_raw not published"); 180 return; 181 } 182 183 Run(); 184 fMessenger = new BMessenger(this); 185 186 if (Lock()) { 187 entry_ref ref; 188 entry.GetRef(&ref); 189 fRoot = new WatchedEntry(fRoster, fMessenger, &ref); 190 Unlock(); 191 } 192 } 193 194 195 void 196 RosterLooper::Stop() 197 { 198 Lock(); 199 delete fRoot; 200 Quit(); 201 } 202 203 204 void 205 RosterLooper::MessageReceived(BMessage *message) 206 { 207 int32 opcode; 208 if (message->FindInt32("opcode", &opcode) < B_OK) 209 return; 210 211 switch (opcode) { 212 case B_ENTRY_CREATED: { 213 dev_t device; 214 ino_t directory; 215 const char *name; 216 if (message->FindInt32("device", &device) < B_OK 217 || message->FindInt64("directory", &directory) < B_OK 218 || message->FindString("name", &name) < B_OK) 219 break; 220 221 entry_ref ref(device, directory, name); 222 fRoot->EntryCreated(&ref); 223 break; 224 } 225 226 case B_ENTRY_REMOVED: { 227 ino_t node; 228 if (message->FindInt64("node", &node) < B_OK) 229 break; 230 231 fRoot->EntryRemoved(node); 232 break; 233 } 234 } 235 } 236 237 238 BUSBRoster::BUSBRoster() 239 : fLooper(NULL) 240 { 241 } 242 243 244 BUSBRoster::~BUSBRoster() 245 { 246 Stop(); 247 } 248 249 250 void 251 BUSBRoster::Start() 252 { 253 if (fLooper) 254 return; 255 256 fLooper = new RosterLooper(this); 257 } 258 259 260 void 261 BUSBRoster::Stop() 262 { 263 if (!fLooper) 264 return; 265 266 ((RosterLooper *)fLooper)->Stop(); 267 fLooper = NULL; 268 } 269 270 271 // definition of reserved virtual functions 272 void BUSBRoster::_ReservedUSBRoster1() {}; 273 void BUSBRoster::_ReservedUSBRoster2() {}; 274 void BUSBRoster::_ReservedUSBRoster3() {}; 275 void BUSBRoster::_ReservedUSBRoster4() {}; 276 void BUSBRoster::_ReservedUSBRoster5() {}; 277