#define HID_INTERNAL
#include <hid.h>
#include <hid_helpers.h>
#include <os.h>
#include <debug.h>
#include <assert.h>
enum USBMatchFlags {
USB_MATCH_NONE = 0x0,
USB_MATCH_VENDOR = 0x1,
USB_MATCH_PRODUCT = 0x2,
USB_MATCH_CUSTOM = 0x4,
USB_MATCH_ALL = USB_MATCH_VENDOR | USB_MATCH_PRODUCT | USB_MATCH_CUSTOM
};
static unsigned int hid_compare_usb_device(struct usb_dev_handle const* dev_h,
HIDInterfaceMatcher const* const match)
{
ASSERT(dev_h);
ASSERT(match);
unsigned int ret = USB_MATCH_NONE;
TRACE("comparing match specifications to USB device...");
struct usb_device const* dev = usb_device((usb_dev_handle*)dev_h);
TRACE("inspecting vendor ID...");
if (dev->descriptor.idVendor > 0 &&
(dev->descriptor.idVendor & match->vendor_id) == match->vendor_id) {
TRACE("match on vendor ID: 0x%04x.", dev->descriptor.idVendor);
ret |= USB_MATCH_VENDOR;
}
else TRACE("no match on vendor ID.");
TRACE("inspecting product ID...");
if ((dev->descriptor.idProduct & match->product_id) == match->product_id) {
TRACE("match on product ID: 0x%04x.", dev->descriptor.idProduct);
ret |= USB_MATCH_PRODUCT;
}
else TRACE("no match on product ID.");
if (match->matcher_fn) {
TRACE("calling custom matching function...");
if ((*match->matcher_fn)(dev_h, match->custom_data, match->custom_data_length)) {
TRACE("match on custom matching function.");
ret |= USB_MATCH_CUSTOM;
}
else TRACE("no match on custom matching function.");
}
else {
TRACE("no custom matching function supplied.");
ret |= USB_MATCH_CUSTOM;
}
return ret;
}
static hid_return hid_find_usb_device(HIDInterface* const hidif,
HIDInterfaceMatcher const* const match)
{
ASSERT(!hid_is_opened(hidif));
ASSERT(match);
/* WARNING: not thread-safe. usb_busses in libusb/usb.c is a global
* variable.
*/
struct usb_bus *usbbus = usb_get_busses();
struct usb_device *usbdev;
TRACE("enumerating USB busses...");
for (; usbbus; usbbus = usbbus->next) {
TRACE("enumerating USB devices on bus %s...", usbbus->dirname);
for (usbdev = usbbus->devices; usbdev; usbdev=usbdev->next) {
snprintf(hidif->id, sizeof(hidif->id), "%s/%s[%d]",
usbbus->dirname, usbdev->filename, hidif->interface);
TRACE("inspecting USB device %s...", hidif->id);
usb_dev_handle *usbdev_h = usb_open(usbdev);
if (usbdev_h) {
usb_claim_interface(usbdev_h, hidif->interface);
unsigned int flags = hid_compare_usb_device(usbdev_h, match);
if (flags == USB_MATCH_ALL) {
NOTICE("found a matching USB device %s.", hidif->id);
hidif->dev_handle = usbdev_h;
hidif->device = usb_device(usbdev_h);
return HID_RET_SUCCESS;
}
if (!(flags & USB_MATCH_VENDOR)) {
NOTICE("vendor 0x%04x of USB device %s does not match 0x%04x.",
usbdev->descriptor.idVendor, hidif->id, match->vendor_id);
}
else if (!(flags & USB_MATCH_PRODUCT)) {
NOTICE("product 0x%04x of USB device %s does not match 0x%04x.",
usbdev->descriptor.idProduct, hidif->id, match->product_id);
}
else if (!(flags & USB_MATCH_CUSTOM)) {
NOTICE("custom matching function returned false on %s.", hidif->id);
}
//usb_release_interface(usbdev_h, hidif->interface);
usb_close(usbdev_h);
}
else {
ERROR("failed to open USB device %s", hidif->id);
return HID_RET_FAIL_OPEN_DEVICE;
}
}
}
WARNING("no matching USB device found.");
return HID_RET_DEVICE_NOT_FOUND;
}
static hid_return hid_get_usb_handle(HIDInterface* const hidif,
HIDInterfaceMatcher const* const match)
{
ASSERT(!hid_is_opened(hidif));
ASSERT(match);
TRACE("acquiring handle for a USB device...");
hid_return ret = hid_find_usb_device(hidif, match);
if (ret != HID_RET_SUCCESS) {
hidif->dev_handle = NULL;
hidif->device = NULL;
return ret;
}
return HID_RET_SUCCESS;
}
hid_return hid_open(HIDInterface* const hidif, int const interface,
HIDInterfaceMatcher const* const matcher)
{
if (!hid_is_initialised()) {
ERROR("cannot open HIDInterface when HID library has not been initialised.");
return HID_RET_NOT_INITIALISED;
}
if (!hidif) {
ERROR("cannot open NULL HIDInterface.");
return HID_RET_INVALID_PARAMETER;
}
if (hid_is_opened(hidif)) {
ERROR("cannot open already opened HIDInterface %s.", hidif->id);
return HID_RET_DEVICE_ALREADY_OPENED;
}
if (!matcher) {
ERROR("cannot match against NULL HIDInterfaceMatcher.");
return HID_RET_INVALID_PARAMETER;
}
hidif->interface = interface;
TRACE("opening a device interface according to matching criteria...");
hid_return ret = hid_get_usb_handle(hidif, matcher);
if (ret != HID_RET_SUCCESS) return ret;
TRACE("claiming USB device %s.", hidif->id);
if (usb_claim_interface(hidif->dev_handle, interface) < 0) {
WARNING("failed to claim USB device %s.", hidif->id);
hid_close(hidif);
return HID_RET_FAIL_CLAIM_IFACE;
}
NOTICE("successfully claimed USB device %s.", hidif->id);
ret = hid_prepare_interface(hidif);
if (ret != HID_RET_SUCCESS) return ret;
NOTICE("successfully opened USB device %s.", hidif->id);
return HID_RET_SUCCESS;
}
hid_return hid_force_open(HIDInterface* const hidif, int const interface,
HIDInterfaceMatcher const* const matcher, unsigned short retries)
{
if (!hid_is_initialised()) {
ERROR("cannot open HIDInterface when HID library has not been initialised.");
return HID_RET_NOT_INITIALISED;
}
if (!hidif) {
ERROR("cannot open NULL HIDInterface.");
return HID_RET_INVALID_PARAMETER;
}
if (hid_is_opened(hidif)) {
ERROR("cannot open already opened HIDInterface %s.", hidif->id);
return HID_RET_DEVICE_ALREADY_OPENED;
}
if (!matcher) {
ERROR("cannot match against NULL HIDInterfaceMatcher.");
return HID_RET_INVALID_PARAMETER;
}
hidif->interface = interface;
TRACE("forcefully opening a device interface "
"according to matching criteria...");
hid_return ret = hid_get_usb_handle(hidif, matcher);
if (ret != HID_RET_SUCCESS) return ret;
TRACE("claiming USB device %s.", hidif->id);
ret = hid_os_force_claim(hidif, interface, matcher, retries);
if (ret != HID_RET_SUCCESS) {
WARNING("failed to claim USB device %s.", hidif->id);
hid_close(hidif);
return ret;
}
NOTICE("successfully claimed USB device %s.", hidif->id);
ret = hid_prepare_interface(hidif);
if (ret != HID_RET_SUCCESS) return ret;
NOTICE("successfully opened USB device %s.", hidif->id);
return HID_RET_SUCCESS;
}
hid_return hid_close(HIDInterface* const hidif)
{
int ret = -1;
if (hid_is_opened(hidif)) {
TRACE("closing USB device %s...", hidif->id);
#if 0
TRACE("releasing USB device %s...", hidif->id);
if (usb_release_interface(hidif->dev_handle, hidif->interface) < 0)
WARNING("failed to release USB device %s.", hidif->id);
#endif
TRACE("closing handle of USB device %s...", hidif->id);
if ((ret = usb_close(hidif->dev_handle)) < 0) {
WARNING("failed to close USB device %s.", hidif->id);
}
else {
NOTICE("successfully closed USB device %s.", hidif->id);
}
}
else WARNING("attempt to close unopened USB device %s.", hidif->id);
if (hidif->hid_parser) hid_reset_parser(hidif);
TRACE("freeing memory allocated for HID parser...");
if(hidif->hid_parser) free(hidif->hid_parser);
if(hidif->hid_data) free(hidif->hid_data);
TRACE("resetting HIDInterface...");
hid_reset_HIDInterface(hidif);
if (ret < 0) return HID_RET_FAIL_CLOSE_DEVICE;
return HID_RET_SUCCESS;
}
bool hid_is_opened(HIDInterface const* hidif)
{
if (!hidif) WARNING("attempt to query open status of NULL HIDInterface.");
return hidif && hidif->dev_handle;
}
/* COPYRIGHT --
*
* This file is part of libhid, a user-space HID access library.
* libhid is (c) 2003-2005
* Martin F. Krafft <libhid@pobox.madduck.net>
* Charles Lepple <clepple+libhid@ghz.cc>
* Arnaud Quette <arnaud.quette@free.fr> && <arnaud.quette@mgeups.com>
* and distributed under the terms of the GNU General Public License.
* See the file ./COPYING in the source distribution for more information.
*
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
syntax highlighted by Code2HTML, v. 0.9.1