diff options
author | Lars-Dominik Braun <lars@6xq.net> | 2012-07-05 16:53:55 +0200 |
---|---|---|
committer | Lars-Dominik Braun <lars@6xq.net> | 2012-07-05 16:53:55 +0200 |
commit | a5eb4ba1296c6279e5535bf3bcc1f1796707f6c6 (patch) | |
tree | f364b89467c2a38ce81e6ca0f2985d7a863c570e /src/device.c | |
download | lshidpp-a5eb4ba1296c6279e5535bf3bcc1f1796707f6c6.tar.gz lshidpp-a5eb4ba1296c6279e5535bf3bcc1f1796707f6c6.tar.bz2 lshidpp-a5eb4ba1296c6279e5535bf3bcc1f1796707f6c6.zip |
Initial import
Diffstat (limited to 'src/device.c')
-rw-r--r-- | src/device.c | 265 |
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; +} + |