summaryrefslogtreecommitdiff
path: root/src/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/device.c')
-rw-r--r--src/device.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/src/device.c b/src/device.c
new file mode 100644
index 0000000..4f92599
--- /dev/null
+++ b/src/device.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2012
+ * Lars-Dominik Braun <lars@6xq.net>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+#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;
+}
+