/* * Copyright (c) 2012 * Lars-Dominik Braun * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include #include #include #include "device.h" #include "usb.h" /* free hid++ device handle */ void hidppDeviceDestroy (hidppDevice_t * const d) { assert (d != NULL); free (d->features); free (d->name); free (d->firmware); memset (d, 0, sizeof (*d)); } /* populate device handle */ void hidppDeviceInit (hidppDevice_t * const d, libusb_device_handle * const usbDev, const hidppDeviceId_t id) { hidppPacket_t rp; assert (d != NULL); assert (usbDev != NULL); memset (d, 0, sizeof (*d)); d->usbDev = usbDev; d->id = id; /* send ping/get version */ hidppUsbRequest (d, HIDPP_FEATURE_ROOT, 0x1, NULL, 0, &rp); if (rp.error == HIDPP_PERROR_UNKNOWN) { /* old hid++ 1.0 device */ d->hidVersion.major = 1; d->hidVersion.minor = 0; } else { d->hidVersion.major = rp.args[0]; d->hidVersion.minor = rp.args[1]; } /* get featureIdx of 0x0001 (IFeatureSet) */ hidppUsbRequest (d, HIDPP_FEATURE_ROOT, 0x0, (const uint8_t *) "\x00\x01\x00", 3, &rp); /* temporary features table */ d->featuresCount = rp.args[0]+1; d->features = calloc (d->featuresCount, sizeof (*d->features)); assert (d->features != NULL); d->features[d->featuresCount-1].id = HIDPP_FEATURE_SET; /* get features count */ hidppUsbRequest (d, HIDPP_FEATURE_SET, 0, NULL, 0, &rp); /* return value does not count feature idx 0 */ d->featuresCount = rp.args[0]+1; d->features = realloc (d->features, d->featuresCount * sizeof (*d->features)); assert (d->features != NULL); /* populate feature index table, index x is reserved for IRoot */ for (uint8_t f = 1; f < d->featuresCount; f++) { /* get feature */ hidppUsbRequest (d, HIDPP_FEATURE_SET, 0x1, &f, 1, &rp); /* FIXME: what about big-endian machines? */ d->features[f].id = rp.args[0]<<8 | rp.args[1]; d->features[f].flags = rp.args[2]; } /* device type */ hidppUsbRequest (d, HIDPP_FEATURE_DEVICE_INFO, 0x2, NULL, 0, &rp); d->type = rp.args[0]; /* device name */ hidppUsbRequest (d, HIDPP_FEATURE_DEVICE_INFO, 0x0, NULL, 0, &rp); size_t len = rp.args[0]; d->name = calloc (len+1, sizeof (*d->name)); do { uint8_t pos = strlen (d->name); hidppUsbRequest (d, HIDPP_FEATURE_DEVICE_INFO, 0x1, &pos, 1, &rp); strcat (d->name, (char *) rp.args); /* FIXME: ugly */ } while (strlen (d->name) < len); /* firmware versions */ hidppUsbRequest (d, HIDPP_FEATURE_FIRMWARE_INFO, 0x0, NULL, 0, &rp); d->firmwareCount = rp.args[0]; d->firmware = calloc (d->firmwareCount, sizeof (*d->firmware)); for (uint8_t i = 0; i < d->firmwareCount; i++) { hidppUsbRequest (d, HIDPP_FEATURE_FIRMWARE_INFO, 0x1, &i, 1, &rp); memcpy (d->firmware[i].prefix, &rp.args[1], 3); d->firmware[i].version = rp.args[4]<<8 | rp.args[5]; d->firmware[i].build = rp.args[6]<<8 | rp.args[7]; } } const char *hidppDeviceTypeToStr (const hidppDeviceType_t t) { switch (t) { case HIDPP_DEV_KEYBOARD: return "keyboard"; break; case HIDPP_DEV_REMOTE_CONTROL: return "remote control"; break; case HIDPP_DEV_NUMPAD: return "numpad"; break; case HIDPP_DEV_MOUSE: return "mouse"; break; case HIDPP_DEV_TOUCHPAD: return "touchpad"; break; case HIDPP_DEV_TRACKBALL: return "trackball"; break; case HIDPP_DEV_PRESENTER: return "presenter"; break; case HIDPP_DEV_RECEIVER: /* FIXME: unifying receiver? */ return "receiver"; break; } return "unknown"; } const char *hidppFirmwareTypeToStr (const hidppFirmwareType_t t) { switch (t) { case HIDPP_FW_TYPE_MAIN: return "Firmware version"; break; case HIDPP_FW_TYPE_BOOT: return "Bootloader version"; break; case HIDPP_FW_TYPE_HARDWARE: return "Hardware version"; break; } return "unknown version"; } const char *hidppFeatureIdToStr (const hidppFeatureId_t f) { switch (f) { case HIDPP_FEATURE_ROOT: return "root"; break; case HIDPP_FEATURE_SET: return "list features"; break; case HIDPP_FEATURE_FIRMWARE_INFO: return "firmware info"; break; case HIDPP_FEATURE_DEVICE_INFO: return "device info"; break; case HIDPP_FEATURE_BATTERY_STATUS: return "battery status"; break; case HIDPP_FEATURE_PROGRAMMABLE_KEYS: return "list programmable keys"; break; case HIDPP_FEATURE_WIRELESS_STATUS: return "wireless status"; break; } return "unknown"; } void hidppDevicePrint (const hidppDevice_t * const d) { printf ("Device:\n" " Name: %s\n" " Type: %s (%u)\n" " HID++ version: %u.%u\n", d->name, hidppDeviceTypeToStr (d->type), d->type, d->hidVersion.major, d->hidVersion.minor); for (size_t i = 0; i < d->firmwareCount; i++) { const hidppFirmware_t * const f = &d->firmware[i]; printf (" %s: %s.%03x.%03x.%05x\n", hidppFirmwareTypeToStr (i), f->prefix, f->version>>8, f->version&0xff, f->build); } /* ignoring the first feature */ printf (" Features: %zu\n", d->featuresCount-1); for (uint8_t fIdx = 1; fIdx < d->featuresCount; fIdx++) { const hidppFeature_t * const f = &d->features[fIdx]; printf (" Feature: %s (%u)\n" " Feature id: 0x%04x\n" " Flags:%s%s%s (0x%x)\n", hidppFeatureIdToStr (f->id), fIdx, f->id, f->flags & HIDPP_FF_OBSOLETE ? " obsolete" : "", f->flags & HIDPP_FF_HIDDEN ? " hidden" : "", f->flags & HIDPP_FF_LOGITECH ? " logitech reserved" : "", f->flags); } } /* translate global feature id to device-dependent index */ bool hidppFeatureIdToIdx (const hidppDevice_t * const d, const hidppFeatureId_t id, uint8_t * const retIdx) { assert (d != NULL); /* 16 bits */ assert (id < (1<<16)); assert (retIdx != NULL); /* root feature is always at 0 */ if (id == HIDPP_FEATURE_ROOT) { *retIdx = 0; return true; } /* FIXME: hashtable? */ for (uint8_t idx = 0; idx < d->featuresCount; idx++) { if (id == d->features[idx].id) { *retIdx = idx; return true; } } return false; }