/* * C++ API and class definition for libdevreg. * * (Use libdevreg.h for ANSI C) */ #ifndef LIBDEVREGPP_H #define LIBDEVREGPP_H #include #include #include #include using std::string; using std::map; using std::vector; namespace DevReg { class Device; class DeviceRegistry; /** * Exception class thrown for when a function/method cannot * read the device registry. */ class ReadException { private: string msg; public: ReadException(const string &m) : msg(m) { } const string toString() const { return msg; } }; const int MAX_STRING_SIZE = 4096; /** * Returns the integer contained in the given file as decimal. * @param filename the name of the file * @return the integer that has been read * @exception ReadException if the file cannot be opened or read */ int readInteger(const string &filename) throw (ReadException); /** * Returns the unsigned long contained in the given file in * hexadecimal format. * @param filename the name of the file * @return the unsigned long that has been read * @exception ReadException if the file cannot be opened or read */ unsigned long readULong(const string &filename) throw (ReadException); /** * Returns the first line of the given file (without \n) * @param filename the name of the file * @return the first line of the file * @exception ReadException if the file cannot be opened or read */ string readLine(const string &filename) throw (ReadException); /** * Reads a string from the given file, looks it up in the NULL-terminated * value table. Throws exception if string wasnt found, otherwise * returns index of the string in the table. * @param filename the name of the file * @param value a NULL-terminated array of 0-terminated strings containing * the possible values * @return the index of the string * @exception ReadException if the file cannot be opened or read, or the read * string is not contained in the array */ int readEnum(const string &filename, const char **values) throw (ReadException); /** * Returns true if the given file or dir exists. * @param filename the name of the file * @return true if the file exists */ bool exists(const string &filename); /** * Reads changecount from the given file and returns it. * If pfd is set and points to a number < 1 it will write the file * descriptor to pfd and keep it open (so you can poll/select for * new changes). If pfd is set and points to a number >=0 it will read * the counter from this file (this also resets the fd so you can * poll/select) * @param filename the name of the file * @param pfd if not 0 the open file descriptor will be written here. * if it points to a non-negative number it will be used as a * file descriptor * @return the changecount value */ int readChangecount(const string &filename, int *pfd = 0) throw (ReadException); inline string operator+(const string &s, int i) { char buf[16]; sprintf(buf, "%d", i); return s + buf; } /** * DeviceNode represents a device node (/dev files). * * All returned references are valid till the next refresh of the * the registry. */ class DeviceNode { private: string interface; string filename; friend class Device; DeviceNode(const string &interface, const string &filename); public: /** * Returns a reference to the interface of the device file. * @return the reference to the interface */ const string &getInterface() const; /** * If the filename is known returns the filename of the * device relative to the device directory (e.g. /dev). * @return a reference to the filename */ const string &getFilename() const; }; /** * Describes the location of a device. VIRTUAL means that there is * no real device the user can see, like the USB root hub. */ enum LocationType { INTERNAL = 0, EXTERNAL = 1, VIRTUAL = 2, UNKNOWN = 3 }; /** * Device represents a physical device. A Device can have * several subdevices (like two controller on a single card) * and children (other devices connected to this one, like a hub). * * All returned pointers and references are valid till the next * refresh of the the registry. */ class Device { private: Device *parent; Device *superdevice; vector subdevices; vector children; vector nodes; string dir, bus, type, deviceid; string model, vendor, location_desc; string superdevice_id, parent_id; enum LocationType location_type; friend class DeviceRegistry; Device(const string &dir) throw (ReadException); ~Device(); public: /** * Returns the parent of the device * @return the parent of the device or 0 if it is top-level */ const Device *getParent() const; /** * Returns the superdevice of the device * @return the superdevice of the device or 0 if it is * not a subdevice */ const Device *getSuperDevice() const; /** * Returns the topmost device in the subdevice hierarchy. * If the device does not have a superdevice, the device itself * is returned. When showing the user devices to select, you * should usually call this method instead of presenting a * subdevice to the user. * @return the superdevice of the device */ const Device *getTopmostDevice() const; /** * Returns a reference to the list of all subdevices * @return the reference to the subdevices */ const vector &getAllSubDevices() const; /** * Returns a reference to the list of all children * @return the reference to the children */ const vector &getAllChildren() const; /** * Returns a reference to the list of all device nodes * @return the reference to the device nodes */ const vector &getAllDeviceNodes() const; /** * Returns a reference to the device's devreg directory. * You should use this if you want to get bus-specific * data from the device. * @return reference to the directory (without trailing slash) */ const string &getDir() const; /** * Returns a reference to the device's bus. * @return reference to the bus */ const string &getBus() const; /** * Returns a reference to the device's type. * @return reference to the type */ const string &getType() const; /** * Returns a reference to the device id. * @return reference to the device id */ const string &getDeviceId() const; /** * Returns a reference to the device's model. * @return reference to the model */ const string &getModel() const; /** * Returns a reference to the device's vendor. * @return reference to the vendor */ const string &getVendor() const; /** * Returns a reference to the device's location description. * @return reference to the location */ const string &getLocation() const; /** * Returns the device's location type * @return the location type */ LocationType getLocationType() const; }; /** * The DeviceRegistry represents the kernel's device registry * in memory. */ class DeviceRegistry { private: string filename; vector device_list; map > deviceid_map; map > deviceidfuzzy_map; map > interface_map; map > bus_map; int lastChangecount; void read(const string &dir, int *fd) throw (ReadException); void cleanup(); void crosslink(); void putInMaps(Device *d); public: ~DeviceRegistry(); /** * Creates a new snapshot of the DeviceRegistry. * @param dir the devreg directory, default is /proc/devreg. * @exception ReadException if the directory cannot be read or * parsed */ DeviceRegistry(const string &dir = "/proc/devreg") throw (ReadException); /** * Refreshes the device-registry by re-reading the devreg * directory and creating a new snapshot. This invalidates all * pointers and references. The refresh call may do nothing * if the registry hasn't changes since. * @param if not 0 this should point to a file descriptor * for the changecount. You can use it to select/poll on * it for errors. An error event means that the device * registry has changed and you should do a refresh. If the * value is negative the changecount file will be opened * and the new file descriptor written here * @exception ReadException if the devreg directory cannot be * read or parsed */ void refresh(int *fd = 0) throw (ReadException); /** * Returns the device with the given deviceid. * @param deviceid the deviceid to find * @param onlyExact return only exact (same serial number and * location) matches * @param multiMatch if true the method will return a device * even if there are several matches. If false and there * are several matches the method will return 0. * @return the first match or 0 if there was no match or * there are several matches and multiMatch was * turned off */ Device *getDeviceById(const string &deviceid, bool onlyExact = false, bool multiMatch = true) const; /** * Finds all devices with the given deviceid and writes * them into the given list. * @param deviceid the deviceid to find * @param devlist all matching devices will be written here * @param onlyExact return only exact (same serial number and * location) matches * @return true if there was at least one EXACT match, * false otherwise */ bool getDevicesById(const string &deviceid, vector &devlist, bool onlyExact = false) const; /** * Finds all devices that have at least one device file * that implements the given interface. Each device is * listed only once. * @param interface the interface to find * @param devlist all matching devices will be written here * @return true if there was at least one match, false * otherwise */ bool getDevicesByInterface(const string &interface, vector &devlist) const; /** * Finds all root devices of the given bus and writes them * into the list. (Does not write the children or subdevices * of the root devices). * @param the bus the requested bus * @param devlist all matching root devices will be written * here * @return true if there was at least one match, false * otherwise */ bool getDevicesByBus(const string &bus, vector &devlist) const; /** * Finds all root devices and writes them into the list. * (Does not write the children or subdevices of the root * devices). * @param devlist all matching root devices will be written * here * @return true if there was at least one match, false * otherwise */ bool getAllRootDevices(vector &devlist) const; }; }; #endif