+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/hidraw.h>
+
+typedef unsigned char byte;
+typedef unsigned int uns;
+
+static void parse(byte *desc, uns size)
+{
+ byte *end = desc + size;
+ uns indent = 0;
+
+ while (desc < end) {
+ uns flags = *desc++;
+ if (flags == 0xfe) {
+ printf("FATAL: Unsupported long item found.\n");
+ return;
+ }
+ if ((flags & 0x0c) == 0x0c) {
+ printf("FATAL: Unsupported item type 3.\n");
+ return;
+ }
+ const uns sizes[4] = { 0, 1, 2, 4 };
+ uns size = sizes[flags & 3];
+ if (desc + size > end) {
+ printf("FATAL: Truncated item.\n");
+ return;
+ }
+ uns val = 0;
+ for (uns i=0; i<size; i++)
+ val |= *desc++ << (8*i);
+
+ printf("%*s%c%x[%d:%08x] ", indent, "", "MGL?"[(flags >> 2) & 3], flags >> 4, size, val);
+ switch (flags & ~3) {
+ /* Main */
+ case 0x80: printf("Input\n");
+ break;
+ case 0x90: printf("Output\n");
+ break;
+ case 0xa0: printf("Collection (type %d) {\n", val);
+ indent += 4;
+ break;
+ case 0xb0: printf("Feature\n");
+ break;
+ case 0xc0: printf("} EndCollection\n");
+ if (indent > 0)
+ indent -= 4;
+ else
+ printf("WARNING: Unbalanced collections!\n");
+ break;
+
+ /* Global */
+ case 0x04: printf("UsagePage %04x\n", val);
+ break;
+ case 0x14: printf("LogicalMin %d\n", val);
+ break;
+ case 0x24: printf("LogicalMax %d\n", val);
+ break;
+ case 0x34: printf("PhysicalMin %d\n", val);
+ break;
+ case 0x44: printf("PhysicalMax %d\n", val);
+ break;
+ case 0x54: printf("UnitExponent\n");
+ break;
+ case 0x64: printf("Unit\n");
+ break;
+ case 0x74: printf("ReportSize %d\n", val);
+ break;
+ case 0x84: printf("ReportID %d\n", val);
+ break;
+ case 0x94: printf("ReportCount %d\n", val);
+ break;
+ case 0xa4: printf("PUSH\n");
+ break;
+ case 0xb4: printf("POP\n");
+ break;
+
+ /* Local */
+ case 0x08: printf("Usage %04x\n", val);
+ break;
+ case 0x18: printf("UsageMin %04x\n", val);
+ break;
+ case 0x28: printf("UsageMax %04x\n", val);
+ break;
+ case 0x38: printf("DesignatorIndex %d\n", val);
+ break;
+ case 0x48: printf("DesignatorMin %d\n", val);
+ break;
+ case 0x58: printf("DesignatorMax %d\n", val);
+ break;
+ case 0x78: printf("StringIndex %d\n", val);
+ break;
+ case 0x88: printf("StringMin %d\n", val);
+ break;
+ case 0x98: printf("StringMax %d\n", val);
+ break;
+ case 0xa8: printf("Delimiter %s\n", (val==0 ? "open" : val==1 ? "close" : "???"));
+ break;
+
+ /* Other */
+ default: printf("?\n");
+ }
+ }
+
+ if (indent)
+ printf("WARNING: Unbalanced collections!\n");
+}
+
+int main(void)
+{
+ int fd = open("/dev/hidraw1", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open hidraw: %m\n");
+ return 1;
+ }
+
+ int size;
+ if (ioctl(fd, HIDIOCGRDESCSIZE, &size) < 0) {
+ fprintf(stderr, "Cannot get desc size: %m\n");
+ return 1;
+ }
+ printf("Detected descriptor size %d\n", size);
+
+ struct hidraw_report_descriptor desc;
+ desc.size = size;
+ if (ioctl(fd, HIDIOCGRDESC, &desc) < 0) {
+ fprintf(stderr, "Cannot get desc contents: %m\n");
+ return 1;
+ }
+ printf("Read %d bytes\n", desc.size);
+
+ struct hidraw_devinfo din;
+ if (ioctl(fd, HIDIOCGRAWINFO, &din) < 0) {
+ fprintf(stderr, "Cannot get raw info: %m\n");
+ return 1;
+ }
+ printf("bustype: %d, id=%04x:%04x\n", din.bustype, (unsigned short) din.vendor, (unsigned short) din.product);
+
+ parse(desc.value, size);
+ return 0;
+}