// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*- #ifndef __USBPP_HEADER__ #define __USBPP_HEADER__ #include #include #include /* * The following usb.h function is not wrapped yet: * char *usb_strerror(void); */ /** * \brief Classes to access Universal Serial Bus devices * * The USB Namespace provides a number of classes to work * with Universal Serial Bus (USB) devices attached to the * system. * * \author Brad Hards */ namespace USB { class Device; /** * \brief Class representing a device endpoint * * This class represents a device endpoint. You need this class to * perform bulk reads and writes. * */ class Endpoint { /** * Busses is a friend because it fills in the descriptor type * information on initialisation and rescan. */ friend class Busses; public: Endpoint() {}; #ifdef USE_UNTESTED_LIBUSBPP_METHODS /** * \brief Bulk write * * This method performs a bulk transfer to the endpoint. * * \param message is the message to be sent. * \param timeout is the USB transaction timeout in milliseconds * * \returns the number of bytes sent, or a negative value on * failure */ int bulkWrite(QByteArray message, int timeout = 100); /** * \brief Bulk read * * This method performs a bulk transfer from the endpoint. * * \param length is the maximum data transfer required. * \param message is the message that was received. * \param timeout is the USB transaction timeout in milliseconds * * \returns the number of bytes received, or a negative value on * failure */ int bulkRead(int length, unsigned char *message, int timeout = 100); /** * \brief Reset endpoint * * This method resets the endpoint. */ int reset(void); /** * \brief Clear halt * * This method clears a halt (stall) on the endpoint. */ int clearHalt(void); #endif /* USE_UNTESTED_LIBUSBPP_METHODS */ /** * \brief Endpoint descriptor information output * * This method dumps out the various characteristics * of the endpoint to standard output. * * It is mostly useful for debugging. */ void dumpDescriptor(void); private: void setDescriptor(struct usb_endpoint_descriptor); void setParent(Device *parent); u_int8_t m_Length; u_int8_t m_DescriptorType; u_int8_t m_EndpointAddress; u_int8_t m_Attributes; u_int16_t m_MaxPacketSize; u_int8_t m_Interval; u_int8_t m_Refresh; u_int8_t m_SynchAddress; Device *m_parent; }; class AltSetting : public std::list { /** * Busses is a friend because it fills in the descriptor type * information on initialisation and rescan. */ friend class Busses; public: AltSetting() {}; u_int8_t numEndpoints(void); /** * \brief AltSetting descriptor information output * * This method dumps out the various characteristics * of the alternate setting to standard output. * * It is mostly useful for debugging. */ void dumpDescriptor(void); Endpoint *firstEndpoint(void); Endpoint *nextEndpoint(void); Endpoint *lastEndpoint(void); private: std::list::const_iterator iter; void setDescriptor(struct usb_interface_descriptor); /* we don't use a normal usb_interface_descriptor */ /* because that would bring in the endpoint list */ u_int8_t m_Length; u_int8_t m_DescriptorType; u_int8_t m_InterfaceNumber; u_int8_t m_AlternateSetting; u_int8_t m_NumEndpoints; u_int8_t m_InterfaceClass; u_int8_t m_InterfaceSubClass; u_int8_t m_InterfaceProtocol; u_int8_t m_Interface; }; /** * \brief Class representing an interface of a Device * * The Interface class represents a USB interface * for a device attached to a Universal Serial Bus. * * Interfaces are the main element of the USB class * structure. * * \author Brad Hards */ class Interface : public std::list { /** * Busses is a friend because it fills in the descriptor type * information on initialisation and rescan. */ friend class Busses; public: Interface() {}; #ifdef LIBUSB_HAS_GET_DRIVER_NP /** * \brief get the current driver for an interface * * \param driver a string containing the name of the current * driver for the interface. You can typically pass in an empty * string for this. * * \return length of string, or 0 on error. */ int driverName(std::string &driver); #endif #ifdef USE_UNTESTED_LIBUSBPP_METHODS /** * \brief Claim this interface * * This method claims the interface. You have to claim the * interface before performing any operations on the interface (or * on endpoints that are part of the interface). * * \return 0 on success or negative number on error. */ int claim(void); /** * \brief Release this interface * * This method releases the interface. You should release the * interface after all operations on it (and any lower level * endpoints) are completed. * * \return 0 on success or negative number on error. */ int release(void); /** * \brief Set interface alternate setting * * This method sets the interface to a particular AltSetting. * * \param altSettingNumber the AltSetting that the interface * should be changed to. * * \return 0 on success, or a negative number in case of error. */ int setAltSetting(int altSettingNumber); #endif /* USE_UNTESTED_LIBUSBPP_METHODS */ /** * \brief Number of Alternative Settings that this interface has * * This is a simple accessor method that specifies the number * alternative settings that this device interface has. */ u_int8_t numAltSettings(void); /** * \brief First AltSetting for the Interface * * This method returns a pointer to the first AltSetting * for the Interface. * * See nextAltSetting() for an example of how it might be * used. * * \see nextAltSetting(), lastAltSetting(), numAltSettings() */ AltSetting *firstAltSetting(void); /** * \brief Next AltSetting for the Interface * * This method returns a pointer to the next AltSetting * for the Interface. * * If you want to iterate through each AltSetting on * a device, you can use something like the following: * \code * USB::Configuration *this_Configuration; * this_Configuration = device->firstConfiguration(); * for (i=0; i < device->numConfigurations(); i++) { * this_Configuration->dumpDescriptor(); * USB::Interface *this_Interface; * this_Interface = this_Configuration->firstInterface(); * for (j=0; j < this_Configuration->numInterfaces(); j++) { * USB::AltSetting *this_AltSetting; * this_AltSetting = this_Interface->firstAltSetting(); * for (k=0; k < this_Interface->numAltSettings(); k++) { * // do something with this_AltSetting * this_AltSetting = this_Interface->nextAltSetting(); * } * this_Interface = this_Configuration->nextInterface(); * } * this_Configuration = device->nextConfiguration(); * } * \endcode * * \see firstAltSetting(), lastAltSetting(), numAltSettings() */ AltSetting *nextAltSetting(void); /** * \brief Last AltSetting for the Interface * * This method returns a pointer to the last AltSetting * for the Interface. * * \see firstAltSetting(), nextAltSetting(), numAltSettings() */ AltSetting *lastAltSetting(void); private: std::list::const_iterator iter; void setNumAltSettings(u_int8_t); void setParent(Device *parent); u_int8_t m_numAltSettings; Device *m_parent; /* index representing the interface, in this configuration */ int m_interfaceNumber; void setInterfaceNumber(int interfaceNumber); }; /** * \brief Class representing a configuration of a Device * * The Configuration class represents a single configuration * of a device attached to a Universal Serial Bus. * * \author Brad Hards */ class Configuration : public std::list { /** * Busses is a friend because it fills in the descriptor type * information on initialisation and rescan. */ friend class Busses; public: Configuration() {}; /** * \brief Configuration descriptor information output * * This method dumps out the various characteristics * of the configuration to standard output. * * It is mostly useful for debugging. */ void dumpDescriptor(void); /** * \brief Number of Interfaces that this device has * * This is a simple accessor method that specifies the number * Interfaces that this device configuration has. */ u_int8_t numInterfaces(void); /** * \brief First Interface for the Configuration * * This method returns a pointer to the first Interface * for the Configuration. * * See nextInterface() for an example of how it might be * used. * * \see nextInterface(), lastInterface(), numInterfaces() */ Interface *firstInterface(void); /** * \brief Next Interface for the Configuration * * This method returns a pointer to the next Interface * for the Configuration. * * If you want to iterate through each Interface on * a device, you can use something like the following: * \code * USB::Configuration *this_Configuration; * this_Configuration = device->firstConfiguration(); * for (i=0; i < device->numConfigurations(); i++) { * this_Interface = this_Configuration->firstInterface(); * for (j=0; j < this_Configuration->numInterfaces(); j++) { * // do something with this_Interface * this_Interface = this_Configuration->nextInterface(); * } * this_Configuration->nextConfiguration(); * } * \endcode * * \see firstInterface(), lastInterface(), numInterfaces() */ Interface *nextInterface(void); /** * \brief Last Interface for the Configuration * * This method returns a pointer to the last Interface * for the Configuration. * * \see firstInterface(), nextInterface(), numInterfaces() */ Interface *lastInterface(void); private: std::list::const_iterator iter; void setDescriptor(struct usb_config_descriptor); /* we don't use a normal usb_config_descriptor */ /* because that would bring in the interface list */ u_int8_t m_Length; u_int8_t m_DescriptorType; u_int16_t m_TotalLength; u_int8_t m_NumInterfaces; u_int8_t m_ConfigurationValue; u_int8_t m_Configuration; u_int8_t m_Attributes; u_int8_t m_MaxPower; }; /** * \brief Class representing a Device on the Bus * * The Device class represents a single device * attached to a Universal Serial Bus. * * \author Brad Hards */ class Device : public std::list { /** * Busses is a friend because it fills in the descriptor type * information on initialisation and rescan. */ friend class Busses; /** * Interface is a friend because it needs the handle() function to * perform claim(), release(). */ friend class Interface; /** * Endpoint is a friend because it needs the handle() function to * perform reads, writes, and other transactions. */ friend class Endpoint; public: Device() {}; ~Device(); /** * \brief OS representation of filename for this device * * libusb++ provides a uniform way of accessing USB * devices irrespective of the underlying Operation System * representation. If you want to map the libusb++ representation * to the Operating System representation, you can do this * with filename(). * * On Linux, the filename is usually something like 002, which * represents the second device (usually the first real device, * after the root hub pseudo-device) on the bus. * * \see Bus::directoryName() */ std::string fileName(void); /** * \brief The vendor ID number, as provided by the device. * * This method returns a number containing the vendor * (manufacturer) identification number. These are allocated * by the USB Implementers Forum, and you can construct a * lookup based on the number to get the manufacturer's name, * even if the device does not contain a vendor string. * * \see Vendor() */ u_int16_t idVendor(void); /** * \brief The product ID number, as provided by the device. * * This method returns a number containing the product * identification number. These are allocated * by the manufacturer, and should be different on each device. * * \see Product() */ u_int16_t idProduct(void); /** * \brief The product's revision ID, as provided by the device. * * This method returns a number containing the product's revision. * This revision level is nominally binary coded decimal, but * hexadecimal revision levels are not uncommon. The binary coded * decimal version nominally has a major version in the high byte, * and a minor version in the low byte. */ u_int16_t idRevision(void); /** * \brief The device's USB class, as provided by the device. * * This method returns a number containing the device's class. * These are defined by the USB Implementer's Forum. * * A code of Zero is special (and common) - it means that the * class is found in the Interface descriptor, rather than in the * Device descriptor. * * A code of 0xFF is also special (and far too common) - it means * that the manufacturer didn't conform to one of the defined * class specifications, and chose to implement a vendor specified * protocol. * */ u_int8_t devClass(void); /** * \brief The device's USB subclass, as provided by the device. * * This method returns a number containing the device's subclass. * These subclasses are defined by the USB Implementer's Forum, * and only have meaning in the context of a specified class. */ u_int8_t devSubClass(void); /** * \brief The device's USB protocol, as provided by the device. * * This method returns a number containing the device's protocol. * These protocols are defined by the USB Implementer's Forum, and * only have meaning in the context of a specified class and * subclass. */ u_int8_t devProtocol(void); /** * \brief The vendor name string, as provided by the device. * * This method returns a string containing the name of the * device's vendor (manufacturer), as encoded into the device. * * Note that not all devices contain a vendor name, and also * that under some operating systems you may not be able to * read the vendor name without elevated privledges (typically * root privledges). * * \see idVendor() **/ std::string Vendor(void); /** * \brief The product name string, as provided by the device. * * This method returns a string containing the name of the * device's product name, as encoded into the device. * * Note that not all devices contain a product name, and also * that under some operating systems you may not be able to * read the vendor name without elevated privledges (typically * root privledges). * * \see idProduct() **/ std::string Product(void); /** * \brief The serial number string, as provided by the device. * * This method returns a string containing a serial number for * the device, as encoded into the device. * * Note that few devices contain a serial number string, and also * that under some operating systems you may not be able to * read the serial number without elevated privledges (typically * root privledges). The USB specification requires that serial * numbers are unique if they are provided, but adherence to this * requirement by manufacturers is not universal. **/ std::string SerialNumber(void); /** * \brief Number of Configurations that this device has * * This is a simple accessor method that specifies the number * configurations that this device has. */ u_int8_t numConfigurations(void); /** * \brief fetch an arbitrary string from the device * * \param string the string from the device. You can typically * pass in an empty string for this. * \param index the index of the string required * \param lang the language ID to use. Defaults to using the * first language ID. * * \return length of string, or 0 on error. */ int string(std::string &buf, int index, u_int16_t lang=0); /** * \brief First Configuration for the Device * * This method returns a pointer to the first Configuration * for the Device. * * See nextConfiguration() for an example of how it might be * used. */ Configuration *firstConfiguration(void); /** * \brief Next Configuration for the Device * * This method returns a pointer to the next Configuration * for the Device. * * If you want to iterate through each Configuration on * a device, you can use something like the following: * \code * USB::Configuration *this_Configuration; * this_Configuration = device->firstConfiguration(); * for (i=0; i < device->numConfigurations(); i++) { * // do something with this_Configuration * this_Configuration->nextConfiguration(); * } * \endcode */ Configuration *nextConfiguration(void); /** * \brief Last Configuration for the Device * * This method returns a pointer to the last Configuration * for the Device. * */ Configuration *lastConfiguration(void); /** * \brief USB control transfer * * This method performs a standard control transfer to the default * endpoint. See the USB specification for more details on this. * * \param requestType corresponds to the bmRequestType field * in the transfer * \param request corresponds to the bRequest field in the * transfer * \param value corresponds to the wValue field in the transfer * \param index corresponds to the wIndex field in the transfer * \param length corresponds to the wLength field in the transfer * \param payload corresponds to the data phase of a control * transfer * \param timeout is the timeout period for the control transfer, * in milliseconds * * \return number of bytes sent or received, or a negative number * in case of error. */ int controlTransfer(u_int8_t requestType, u_int8_t request, u_int16_t value, u_int16_t index, u_int16_t length, unsigned char *payload, int timeout = 100); #ifdef USE_UNTESTED_LIBUSBPP_METHODS /** * \brief USB device reset * * This method performs a device reset - see USB Specification * 9.1 for how this changes the device state to the Default state. * * \return 0 on success, or a negative number in case of error. */ int reset(void); /** * \brief Set device configuration * * This method sets the device to a particular Configuration. * * \param configurationNumber the configuration that the device * should be changed to. * * \return 0 on success, or a negative number in case of error. */ int setConfiguration(int configurationNumber); #endif /* USE_UNTESTED_LIBUSBPP_METHODS */ private: std::list::const_iterator iter; struct usb_dev_handle *handle(); void setFileName(std::string); void setDescriptor(struct usb_device_descriptor); void setVendor(std::string); void setProduct(std::string); void setSerialNumber(std::string); void setDevHandle(struct usb_dev_handle *); std::string m_fileName; std::string m_Vendor; std::string m_Product; std::string m_SerialNumber; struct usb_device *m_dev; struct usb_dev_handle *m_handle; struct usb_device_descriptor m_descriptor; }; /** * \brief Class representing a single bus on the machine * * This class is essentially a list of Device class instances */ class Bus : public std::list { /** * Busses is a friend because it fills in the directory name * information on initialisation and rescan. */ friend class Busses; public: Bus() {}; /** * \brief OS representation of directory name for this Bus * * libusb++ provides a uniform way of accessing USB * busses irrespective of the underlying Operation System * representation. If you want to map the libusb++ representation * to the Operating System representation, you can do this * with directory name(). * * On Linux, the directoryname is usually something like 003, which * represents the third bus on the host. * * \see Directory::filename() */ std::string directoryName(void); private: std::list::const_iterator iter; void setDirectoryName(std::string); std::string m_directoryName; }; /** * \brief A vendor/product ID pair * * DeviceID provides a list of (vendor, product) identification * pairs. It is intended for use in a list of device numbers to * search for, but there is no reason why it couldn't be used for a * general purpose (vendor,product) tuple if you had some reason for * this. * * The description for Busses::match() provides an example of how * this class might be used. * * \see DeviceIDList, Busses::match() */ class DeviceID { public: DeviceID() {}; /** * \brief Standard constructor * * This constructor takes (vendor, product) tuple, which are * stored away. * * \param vendor the 16 bit vendor number for the device * \param product the 16 bit product number for the device */ DeviceID(u_int16_t vendor, u_int16_t product); /** * \brief vendor number for the device * * This method returns the 16 bit vendor number. */ u_int16_t vendor(void); /** * \brief product number for the device * * This method returns the 16 bit product number. */ u_int16_t product(void); private: u_int16_t m_vendor; u_int16_t m_product; }; /** * \brief A list of vendor/product pairs * * DeviceIDList provides a list of DeviceID classes, which is * essentially a list of (vendor, product) identification pairs. * * \see DeviceID */ typedef std::list DeviceIDList; /** * \brief Class representing all the busses on the machine * * This class is essentially a list of Bus class instances */ class Busses : public std::list { public: Busses(); /** * \brief Update method * * This method can be called to rescan the various devices * attached to the various busses. You should use it to * update if things change. Unfortunately there is no * way to automatically detect this change in a portable way, * so worst case is that you need to call this using some * kind of timer in the background. */ void rescan(void); /** * \brief find all devices with matching device class designator * * This method searches every device on every bus, and returns a * list of pointers to the devices that have a matching device * class code */ std::list match(u_int8_t Class); /** * \brief find all devices with matching device IDs * * This method searches every device on every bus, and returns a * list of pointers to the devices that have a matching device * ID. That is, if the (vendor, product) tuple of a device matches * one of the tuples on the list, then the device will be added to * the list of matches. * * An example of usage is shown below: * \code * USB::Busses buslist; * USB::Device *device; * std::list miceFound; * USB::DeviceIDList mouseList; * * mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC00E)); // Wheel Mouse Optical * mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC012)); // MouseMan Dual Optical * mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC506)); // MX700 Optical Mouse * * miceFound = buslist.match(mouseList); * * for ( device = miceFound.first(); device; device = miceFound.next() ) { * // do something with each mouse that matched * } * FIXME: This is incorrect now * \endcode */ std::list match(DeviceIDList); private: std::list::const_iterator iter; }; class Error { public: private: }; } #endif /* __USBPP_HEADER__ */