From 7b584fbfb8cd9451ecb798c5f27c56b1216b9ca2 Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Sun, 25 Aug 2013 19:22:45 +0200 Subject: Added basic HID descriptors. --- usb/hid.h | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 usb/hid.h diff --git a/usb/hid.h b/usb/hid.h new file mode 100644 index 0000000..eac3f07 --- /dev/null +++ b/usb/hid.h @@ -0,0 +1,227 @@ +#ifndef HID_H +#define HID_H + +struct HID_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescriptorType0; + uint16_t wDescriptorLength0; +} __attribute__((packed)); + +constexpr HID_desc hid_desc( + uint16_t bcdHID, + uint8_t bCountryCode, + uint8_t bNumDescriptors, + uint8_t bDescriptorType, + uint16_t wDescriptorLength + ) { + + return { + sizeof(HID_desc), + 0x21, + bcdHID, + bCountryCode, + bNumDescriptors, + bDescriptorType, + wDescriptorLength + }; +} + +template +struct HID_Item { + uint8_t tag; + T data; +} __attribute__((packed)); + +template <> +struct HID_Item { + uint8_t tag; +} __attribute__((packed)); + +constexpr HID_Item hid_item(uint8_t tag) { + return {tag}; +} + +template +constexpr uint8_t hid_item_data_size() { + static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "item has invalid size"); + + return sizeof(T) == 1 ? 1 : sizeof(T) == 2 ? 2 : 3; +} + +template +constexpr HID_Item hid_item(uint8_t tag, T data) { + return HID_Item{uint8_t(tag | hid_item_data_size()), data}; +} + +namespace UsagePage { + enum _8 : uint8_t { + Undefined, + Desktop, + Simulation, + VR, + Sport, + Game, + Generic, + Keyboard, + LED, + Button, + Ordinal, + }; +} + +constexpr HID_Item usage_page(UsagePage::_8 page) { + return hid_item(0x04, page); +} + +constexpr HID_Item usage_page(uint16_t page) { + return hid_item(0x04, page); +} + +namespace DesktopUsage { + enum _8 : uint8_t { + Undefined, + Gamepad = 0x05, + X = 0x30, + Y, + Z, + Rx, + Ry, + Rz, + }; +} + +enum class Collection : uint8_t { + Physical, + Application, + Logical, +}; + +constexpr HID_Item usage(DesktopUsage::_8 usage) { + return hid_item(0x08, usage); +} + +constexpr HID_Item usage(uint16_t usage) { + return hid_item(0x08, usage); +} + +template +constexpr auto collection(Collection type, R... r) -> decltype(pack(HID_Item(), r..., HID_Item())) { + return pack(hid_item(0xa0, type), r..., hid_item(0xc0)); +} + +constexpr HID_Item usage_minimum(int16_t x) { + return hid_item(0x18, x); +} + +constexpr HID_Item usage_maximum(int16_t x) { + return hid_item(0x28, x); +} + +constexpr HID_Item logical_minimum(int32_t x) { + return hid_item(0x14, x); +} + +constexpr HID_Item logical_maximum(int32_t x) { + return hid_item(0x24, x); +} + +constexpr HID_Item report_count(uint8_t x) { + return hid_item(0x94, x); +} + +constexpr HID_Item report_size(uint8_t x) { + return hid_item(0x74, x); +} + +constexpr HID_Item input(uint8_t x) { + return hid_item(0x80, x); +} + +constexpr HID_Item output(uint8_t x) { + return hid_item(0x90, x); +} + +constexpr HID_Item feature(uint8_t x) { + return hid_item(0xb0, x); +} + +constexpr HID_Item report_id(uint8_t id) { + return hid_item(0x84, id); +} + +template +constexpr auto gamepad(R... r) -> decltype( + pack( + usage_page(UsagePage::Desktop), + usage(DesktopUsage::Gamepad), + collection(Collection::Application, + collection(Collection::Physical, + r... + ) + ) + )) { + return pack( + usage_page(UsagePage::Desktop), + usage(DesktopUsage::Gamepad), + collection(Collection::Application, + collection(Collection::Physical, + r... + ) + ) + ); +} + +constexpr auto buttons(uint8_t num) -> decltype( + pack( + usage_page(UsagePage::Button), + usage_minimum(1), + usage_maximum(num), + logical_minimum(0), + logical_maximum(1), + report_count(num), + report_size(1), + input(0x02) + )) { + return pack( + usage_page(UsagePage::Button), + usage_minimum(1), + usage_maximum(num), + logical_minimum(0), + logical_maximum(1), + report_count(num), + report_size(1), + input(0x02) + ); +} + +constexpr auto padding_in(uint8_t size) -> decltype( + pack( + report_count(1), + report_size(size), + input(0x01) + )) { + return pack( + report_count(1), + report_size(size), + input(0x01) + ); +} + +constexpr auto padding_out(uint8_t size) -> decltype( + pack( + report_count(1), + report_size(size), + output(0x01) + )) { + return pack( + report_count(1), + report_size(size), + output(0x01) + ); +} + +#endif -- cgit v1.2.3