diff --git a/src/userland/hid/include/hid.h b/src/userland/hid/include/hid.h index 7b177fa..313db38 100644 --- a/src/userland/hid/include/hid.h +++ b/src/userland/hid/include/hid.h @@ -16,14 +16,26 @@ int8_t x, y; } __attribute__((packed)) MouseReport; +typedef struct Usage Usage; typedef struct { char *name; uint32_t id; + uint32_t usageCount; + Usage *usages; } UsagePage; extern UsagePage *getUsagePage(uint32_t id); extern void initializeUsagePages(); +typedef struct Usage { + UsagePage *usagePage; + uint32_t id; + char *name; + void (*handle)(int32_t); +} Usage; + +extern Usage *getUsage(UsagePage *usagePage, uint32_t id); + typedef struct { uint32_t padding; uint32_t reportSize, reportCount; @@ -35,10 +47,9 @@ } ReportParserState; typedef struct { - uint8_t usage; + Usage *usage; uint8_t size; int32_t min, max; - UsagePage *usagePage; bool discard, relative, isSigned; } InputReader; diff --git a/src/userland/hid/include/hid.h b/src/userland/hid/include/hid.h index 7b177fa..313db38 100644 --- a/src/userland/hid/include/hid.h +++ b/src/userland/hid/include/hid.h @@ -16,14 +16,26 @@ int8_t x, y; } __attribute__((packed)) MouseReport; +typedef struct Usage Usage; typedef struct { char *name; uint32_t id; + uint32_t usageCount; + Usage *usages; } UsagePage; extern UsagePage *getUsagePage(uint32_t id); extern void initializeUsagePages(); +typedef struct Usage { + UsagePage *usagePage; + uint32_t id; + char *name; + void (*handle)(int32_t); +} Usage; + +extern Usage *getUsage(UsagePage *usagePage, uint32_t id); + typedef struct { uint32_t padding; uint32_t reportSize, reportCount; @@ -35,10 +47,9 @@ } ReportParserState; typedef struct { - uint8_t usage; + Usage *usage; uint8_t size; int32_t min, max; - UsagePage *usagePage; bool discard, relative, isSigned; } InputReader; diff --git a/src/userland/hid/main.c b/src/userland/hid/main.c index 2244f95..c337efe 100644 --- a/src/userland/hid/main.c +++ b/src/userland/hid/main.c @@ -4,9 +4,6 @@ #include REQUEST(checkFocus, "ioManager", "checkFocus"); -REQUEST(moveRelative, "mouse", "moveRelative"); -REQUEST(updateButtons, "mouse", "updateButtons"); - ListElement *hidDevices = NULL; char *collectionTypes[] = { @@ -29,39 +26,9 @@ printf("%pCollection(%s)\n", padding, collectionType); } -char *usage(UsagePage *usagePage, uint32_t data) { - if (usagePage->id != 1) { // Generic Desktop Page - return "Unknown: unimplemented usage page"; - } - switch (data) { - case 0: return "Undefined"; - case 1: return "Pointer"; - case 2: return "Mouse"; - case 3: return "Reserved"; - case 4: return "Joystick"; - case 5: return "Game Pad"; - case 6: return "Keyboard"; - case 7: return "Keypad"; - case 8: return "Multi-axis Controller"; - case 9: return "Tablet PC System Controls"; - case 0x30: return "X"; - case 0x31: return "Y"; - case 0x32: return "Z"; - case 0x33: return "Rx"; - case 0x34: return "Ry"; - case 0x35: return "Rz"; - case 0x36: return "Slider"; - case 0x37: return "Dial"; - case 0x38: return "Wheel"; - case 0x39: return "Hat switch"; - } - return "Unknown"; -} - -void insertInputReader(ReportParserState *state, uint32_t usage, uint32_t data, ListElement **inputReaders) { +void insertInputReader(ReportParserState *state, Usage *usage, uint32_t data, ListElement **inputReaders) { InputReader *reader = malloc(sizeof(InputReader)); reader->size = state->reportSize; - reader->usagePage = state->usagePage; reader->usage = usage; // signed integers are represented as 2s-complement reader->isSigned = state->logicalMin > state->logicalMax; @@ -104,31 +71,31 @@ if (data >> 0 & 1) { // data is constant, no need to keep track of it for (uint32_t i = 0; i < state->reportCount; i++) { - insertInputReader(state, i, data, inputReaders); + insertInputReader(state, getUsage(state->usagePage, i), data, inputReaders); } } else if (usageCount == 1) { - uint8_t currentUsage = U32(listGet(state->usages, 0)); + Usage *usage = listGet(state->usages, 0); printf("%p New input parser has usage %s for all entries\n", state->padding, - usage(state->usagePage, currentUsage) + usage ? usage->name : "Unknown" ); for (uint32_t i = 0; i < state->reportCount; i++) { - insertInputReader(state, currentUsage, data, inputReaders); + insertInputReader(state, usage, data, inputReaders); } } else if (usageCount == state->reportCount) { printf("%p New input has the following usages:\n", state->padding); uint32_t i = 0; - foreach (state->usages, void *, currentUsage, { + foreach (state->usages, Usage *, usage, { printf("%p Interpreting report %i as %s\n", state->padding, i++, - usage(state->usagePage, U32(currentUsage)) + usage ? usage->name : "Unknown" ); - insertInputReader(state, U32(currentUsage), data, inputReaders); + insertInputReader(state, usage, data, inputReaders); }); } else if (usageCount == 0 && (state->usageMax - state->usageMin + 1 == state->reportCount)) { - for (uint32_t currentUsage = state->usageMin; currentUsage <= state->usageMax; currentUsage++) { - insertInputReader(state, currentUsage, data, inputReaders); + for (uint32_t usage = state->usageMin; usage <= state->usageMax; usage++) { + insertInputReader(state, getUsage(state->usagePage, usage), data, inputReaders); } } else { printf("%p Input parser cannot deduce the usage of the reports, having %i reports and %i usages\n", @@ -149,6 +116,7 @@ uint32_t data = *((uint32_t *)read); data &= 0xFFFFFFFF >> ((4 - dataSize) * 8); read += dataSize; + Usage *usage; switch (item >> 2) { case 0: return state.totalBits; @@ -157,8 +125,9 @@ printf("%pUsagePage(%x: %s)\n", state.padding, data, state.usagePage->name); break; case 2: - printf("%pUsage(%x: %s)\n", state.padding, data, usage(state.usagePage, data)); - listAdd(&state.usages, PTR(data)); + usage = getUsage(state.usagePage, data); + printf("%pUsage(%x: %s)\n", state.padding, data, usage ? usage->name : "Unknown"); + listAdd(&state.usages, usage); break; case 0x05: printf("%pLogicalMinimum(%x)\n", state.padding, data); @@ -233,9 +202,8 @@ processedData = (int32_t)(int16_t) data; } } - if (reader->usagePage->id == 1 && reader->usage == 0x30) { - // mouse X axis - moveRelative(processedData, 0); + if (reader->usage) { + reader->usage->handle(processedData); } }); // TODO: sleep for at least endpoint->interval? diff --git a/src/userland/hid/include/hid.h b/src/userland/hid/include/hid.h index 7b177fa..313db38 100644 --- a/src/userland/hid/include/hid.h +++ b/src/userland/hid/include/hid.h @@ -16,14 +16,26 @@ int8_t x, y; } __attribute__((packed)) MouseReport; +typedef struct Usage Usage; typedef struct { char *name; uint32_t id; + uint32_t usageCount; + Usage *usages; } UsagePage; extern UsagePage *getUsagePage(uint32_t id); extern void initializeUsagePages(); +typedef struct Usage { + UsagePage *usagePage; + uint32_t id; + char *name; + void (*handle)(int32_t); +} Usage; + +extern Usage *getUsage(UsagePage *usagePage, uint32_t id); + typedef struct { uint32_t padding; uint32_t reportSize, reportCount; @@ -35,10 +47,9 @@ } ReportParserState; typedef struct { - uint8_t usage; + Usage *usage; uint8_t size; int32_t min, max; - UsagePage *usagePage; bool discard, relative, isSigned; } InputReader; diff --git a/src/userland/hid/main.c b/src/userland/hid/main.c index 2244f95..c337efe 100644 --- a/src/userland/hid/main.c +++ b/src/userland/hid/main.c @@ -4,9 +4,6 @@ #include REQUEST(checkFocus, "ioManager", "checkFocus"); -REQUEST(moveRelative, "mouse", "moveRelative"); -REQUEST(updateButtons, "mouse", "updateButtons"); - ListElement *hidDevices = NULL; char *collectionTypes[] = { @@ -29,39 +26,9 @@ printf("%pCollection(%s)\n", padding, collectionType); } -char *usage(UsagePage *usagePage, uint32_t data) { - if (usagePage->id != 1) { // Generic Desktop Page - return "Unknown: unimplemented usage page"; - } - switch (data) { - case 0: return "Undefined"; - case 1: return "Pointer"; - case 2: return "Mouse"; - case 3: return "Reserved"; - case 4: return "Joystick"; - case 5: return "Game Pad"; - case 6: return "Keyboard"; - case 7: return "Keypad"; - case 8: return "Multi-axis Controller"; - case 9: return "Tablet PC System Controls"; - case 0x30: return "X"; - case 0x31: return "Y"; - case 0x32: return "Z"; - case 0x33: return "Rx"; - case 0x34: return "Ry"; - case 0x35: return "Rz"; - case 0x36: return "Slider"; - case 0x37: return "Dial"; - case 0x38: return "Wheel"; - case 0x39: return "Hat switch"; - } - return "Unknown"; -} - -void insertInputReader(ReportParserState *state, uint32_t usage, uint32_t data, ListElement **inputReaders) { +void insertInputReader(ReportParserState *state, Usage *usage, uint32_t data, ListElement **inputReaders) { InputReader *reader = malloc(sizeof(InputReader)); reader->size = state->reportSize; - reader->usagePage = state->usagePage; reader->usage = usage; // signed integers are represented as 2s-complement reader->isSigned = state->logicalMin > state->logicalMax; @@ -104,31 +71,31 @@ if (data >> 0 & 1) { // data is constant, no need to keep track of it for (uint32_t i = 0; i < state->reportCount; i++) { - insertInputReader(state, i, data, inputReaders); + insertInputReader(state, getUsage(state->usagePage, i), data, inputReaders); } } else if (usageCount == 1) { - uint8_t currentUsage = U32(listGet(state->usages, 0)); + Usage *usage = listGet(state->usages, 0); printf("%p New input parser has usage %s for all entries\n", state->padding, - usage(state->usagePage, currentUsage) + usage ? usage->name : "Unknown" ); for (uint32_t i = 0; i < state->reportCount; i++) { - insertInputReader(state, currentUsage, data, inputReaders); + insertInputReader(state, usage, data, inputReaders); } } else if (usageCount == state->reportCount) { printf("%p New input has the following usages:\n", state->padding); uint32_t i = 0; - foreach (state->usages, void *, currentUsage, { + foreach (state->usages, Usage *, usage, { printf("%p Interpreting report %i as %s\n", state->padding, i++, - usage(state->usagePage, U32(currentUsage)) + usage ? usage->name : "Unknown" ); - insertInputReader(state, U32(currentUsage), data, inputReaders); + insertInputReader(state, usage, data, inputReaders); }); } else if (usageCount == 0 && (state->usageMax - state->usageMin + 1 == state->reportCount)) { - for (uint32_t currentUsage = state->usageMin; currentUsage <= state->usageMax; currentUsage++) { - insertInputReader(state, currentUsage, data, inputReaders); + for (uint32_t usage = state->usageMin; usage <= state->usageMax; usage++) { + insertInputReader(state, getUsage(state->usagePage, usage), data, inputReaders); } } else { printf("%p Input parser cannot deduce the usage of the reports, having %i reports and %i usages\n", @@ -149,6 +116,7 @@ uint32_t data = *((uint32_t *)read); data &= 0xFFFFFFFF >> ((4 - dataSize) * 8); read += dataSize; + Usage *usage; switch (item >> 2) { case 0: return state.totalBits; @@ -157,8 +125,9 @@ printf("%pUsagePage(%x: %s)\n", state.padding, data, state.usagePage->name); break; case 2: - printf("%pUsage(%x: %s)\n", state.padding, data, usage(state.usagePage, data)); - listAdd(&state.usages, PTR(data)); + usage = getUsage(state.usagePage, data); + printf("%pUsage(%x: %s)\n", state.padding, data, usage ? usage->name : "Unknown"); + listAdd(&state.usages, usage); break; case 0x05: printf("%pLogicalMinimum(%x)\n", state.padding, data); @@ -233,9 +202,8 @@ processedData = (int32_t)(int16_t) data; } } - if (reader->usagePage->id == 1 && reader->usage == 0x30) { - // mouse X axis - moveRelative(processedData, 0); + if (reader->usage) { + reader->usage->handle(processedData); } }); // TODO: sleep for at least endpoint->interval? diff --git a/src/userland/hid/usagePages/genericDesktopControls.c b/src/userland/hid/usagePages/genericDesktopControls.c new file mode 100644 index 0000000..4d07b1e --- /dev/null +++ b/src/userland/hid/usagePages/genericDesktopControls.c @@ -0,0 +1,29 @@ +#include + +// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf +// section 4, table 6, page 26 + +REQUEST(moveRelative, "mouse", "moveRelative"); +REQUEST(updateButtons, "mouse", "updateButtons"); + +void handleX(int32_t dx) { + moveRelative(dx, 0); +} + +void handleY(int32_t dy) { + moveRelative(0, dy); +} + +Usage genericDesktopControlsUsages[] = { + { + .id = 0x30, + .handle = handleX, + .name = "X", + }, { + .id = 0x31, + .handle = handleY, + .name = "Y", + }, { + .id = -1, // end tag + } +}; diff --git a/src/userland/hid/include/hid.h b/src/userland/hid/include/hid.h index 7b177fa..313db38 100644 --- a/src/userland/hid/include/hid.h +++ b/src/userland/hid/include/hid.h @@ -16,14 +16,26 @@ int8_t x, y; } __attribute__((packed)) MouseReport; +typedef struct Usage Usage; typedef struct { char *name; uint32_t id; + uint32_t usageCount; + Usage *usages; } UsagePage; extern UsagePage *getUsagePage(uint32_t id); extern void initializeUsagePages(); +typedef struct Usage { + UsagePage *usagePage; + uint32_t id; + char *name; + void (*handle)(int32_t); +} Usage; + +extern Usage *getUsage(UsagePage *usagePage, uint32_t id); + typedef struct { uint32_t padding; uint32_t reportSize, reportCount; @@ -35,10 +47,9 @@ } ReportParserState; typedef struct { - uint8_t usage; + Usage *usage; uint8_t size; int32_t min, max; - UsagePage *usagePage; bool discard, relative, isSigned; } InputReader; diff --git a/src/userland/hid/main.c b/src/userland/hid/main.c index 2244f95..c337efe 100644 --- a/src/userland/hid/main.c +++ b/src/userland/hid/main.c @@ -4,9 +4,6 @@ #include REQUEST(checkFocus, "ioManager", "checkFocus"); -REQUEST(moveRelative, "mouse", "moveRelative"); -REQUEST(updateButtons, "mouse", "updateButtons"); - ListElement *hidDevices = NULL; char *collectionTypes[] = { @@ -29,39 +26,9 @@ printf("%pCollection(%s)\n", padding, collectionType); } -char *usage(UsagePage *usagePage, uint32_t data) { - if (usagePage->id != 1) { // Generic Desktop Page - return "Unknown: unimplemented usage page"; - } - switch (data) { - case 0: return "Undefined"; - case 1: return "Pointer"; - case 2: return "Mouse"; - case 3: return "Reserved"; - case 4: return "Joystick"; - case 5: return "Game Pad"; - case 6: return "Keyboard"; - case 7: return "Keypad"; - case 8: return "Multi-axis Controller"; - case 9: return "Tablet PC System Controls"; - case 0x30: return "X"; - case 0x31: return "Y"; - case 0x32: return "Z"; - case 0x33: return "Rx"; - case 0x34: return "Ry"; - case 0x35: return "Rz"; - case 0x36: return "Slider"; - case 0x37: return "Dial"; - case 0x38: return "Wheel"; - case 0x39: return "Hat switch"; - } - return "Unknown"; -} - -void insertInputReader(ReportParserState *state, uint32_t usage, uint32_t data, ListElement **inputReaders) { +void insertInputReader(ReportParserState *state, Usage *usage, uint32_t data, ListElement **inputReaders) { InputReader *reader = malloc(sizeof(InputReader)); reader->size = state->reportSize; - reader->usagePage = state->usagePage; reader->usage = usage; // signed integers are represented as 2s-complement reader->isSigned = state->logicalMin > state->logicalMax; @@ -104,31 +71,31 @@ if (data >> 0 & 1) { // data is constant, no need to keep track of it for (uint32_t i = 0; i < state->reportCount; i++) { - insertInputReader(state, i, data, inputReaders); + insertInputReader(state, getUsage(state->usagePage, i), data, inputReaders); } } else if (usageCount == 1) { - uint8_t currentUsage = U32(listGet(state->usages, 0)); + Usage *usage = listGet(state->usages, 0); printf("%p New input parser has usage %s for all entries\n", state->padding, - usage(state->usagePage, currentUsage) + usage ? usage->name : "Unknown" ); for (uint32_t i = 0; i < state->reportCount; i++) { - insertInputReader(state, currentUsage, data, inputReaders); + insertInputReader(state, usage, data, inputReaders); } } else if (usageCount == state->reportCount) { printf("%p New input has the following usages:\n", state->padding); uint32_t i = 0; - foreach (state->usages, void *, currentUsage, { + foreach (state->usages, Usage *, usage, { printf("%p Interpreting report %i as %s\n", state->padding, i++, - usage(state->usagePage, U32(currentUsage)) + usage ? usage->name : "Unknown" ); - insertInputReader(state, U32(currentUsage), data, inputReaders); + insertInputReader(state, usage, data, inputReaders); }); } else if (usageCount == 0 && (state->usageMax - state->usageMin + 1 == state->reportCount)) { - for (uint32_t currentUsage = state->usageMin; currentUsage <= state->usageMax; currentUsage++) { - insertInputReader(state, currentUsage, data, inputReaders); + for (uint32_t usage = state->usageMin; usage <= state->usageMax; usage++) { + insertInputReader(state, getUsage(state->usagePage, usage), data, inputReaders); } } else { printf("%p Input parser cannot deduce the usage of the reports, having %i reports and %i usages\n", @@ -149,6 +116,7 @@ uint32_t data = *((uint32_t *)read); data &= 0xFFFFFFFF >> ((4 - dataSize) * 8); read += dataSize; + Usage *usage; switch (item >> 2) { case 0: return state.totalBits; @@ -157,8 +125,9 @@ printf("%pUsagePage(%x: %s)\n", state.padding, data, state.usagePage->name); break; case 2: - printf("%pUsage(%x: %s)\n", state.padding, data, usage(state.usagePage, data)); - listAdd(&state.usages, PTR(data)); + usage = getUsage(state.usagePage, data); + printf("%pUsage(%x: %s)\n", state.padding, data, usage ? usage->name : "Unknown"); + listAdd(&state.usages, usage); break; case 0x05: printf("%pLogicalMinimum(%x)\n", state.padding, data); @@ -233,9 +202,8 @@ processedData = (int32_t)(int16_t) data; } } - if (reader->usagePage->id == 1 && reader->usage == 0x30) { - // mouse X axis - moveRelative(processedData, 0); + if (reader->usage) { + reader->usage->handle(processedData); } }); // TODO: sleep for at least endpoint->interval? diff --git a/src/userland/hid/usagePages/genericDesktopControls.c b/src/userland/hid/usagePages/genericDesktopControls.c new file mode 100644 index 0000000..4d07b1e --- /dev/null +++ b/src/userland/hid/usagePages/genericDesktopControls.c @@ -0,0 +1,29 @@ +#include + +// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf +// section 4, table 6, page 26 + +REQUEST(moveRelative, "mouse", "moveRelative"); +REQUEST(updateButtons, "mouse", "updateButtons"); + +void handleX(int32_t dx) { + moveRelative(dx, 0); +} + +void handleY(int32_t dy) { + moveRelative(0, dy); +} + +Usage genericDesktopControlsUsages[] = { + { + .id = 0x30, + .handle = handleX, + .name = "X", + }, { + .id = 0x31, + .handle = handleY, + .name = "Y", + }, { + .id = -1, // end tag + } +}; diff --git a/src/userland/hid/usagePages/usagePages.c b/src/userland/hid/usagePages/usagePages.c index c70df3a..bd4a661 100644 --- a/src/userland/hid/usagePages/usagePages.c +++ b/src/userland/hid/usagePages/usagePages.c @@ -1,44 +1,73 @@ #include +extern Usage genericDesktopControlsUsages[]; + // https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf // page 14, section 3, table 1: Usage Page Summary UsagePage usagePages[] = { { .name = "Undefined", + .usages = NULL, }, { .name = "Generic Desktop Controls", + .usages = genericDesktopControlsUsages, }, { .name = "Simulation Controls", + .usages = NULL, }, { .name = "VR Controls", + .usages = NULL, }, { .name = "Sport Controls", + .usages = NULL, }, { .name = "Game Controls", + .usages = NULL, }, { .name = "Generic Device Controls", + .usages = NULL, }, { .name = "Keyboard/Keypad", + .usages = NULL, }, { .name = "LEDs", + .usages = NULL, }, { .name = "Button", + .usages = NULL, }, { .name = "Ordinal", + .usages = NULL, }, { .name = "Telephony", + .usages = NULL, }, { .name = "Consumer", + .usages = NULL, }, { .name = "Digitizer", + .usages = NULL, }, { .name = "PID Page", + .usages = NULL, }, }; +void initializeUsages(UsagePage *usagePage) { + if (!usagePage->usages) { + return; + } + uint32_t i = 0; + for (; usagePage->usages[i].id != -1; i++) { + usagePage->usages[i].usagePage = usagePage; + } + usagePage->usageCount = i; +} + void initializeUsagePages() { for (uint32_t i = 0; i < sizeof(usagePages) / sizeof(usagePages[0]); i++) { usagePages[i].id = i; + initializeUsages(&usagePages[i]); } } @@ -48,3 +77,15 @@ } return &usagePages[id]; } + +Usage *getUsage(UsagePage *usagePage, uint32_t id) { + if (!usagePage || !usagePage->usages) { + return NULL; + } + for (uint32_t i = 0; i < usagePage->usageCount; i++) { + if (usagePage->usages[i].id == id) { + return &usagePage->usages[i]; + } + } + return NULL; +}