diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2013-08-25 19:22:45 +0200 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2013-08-25 19:22:45 +0200 |
commit | 7b584fbfb8cd9451ecb798c5f27c56b1216b9ca2 (patch) | |
tree | 23d0dca9fa72cb8b6d50b23852e74f4b0190ff72 | |
parent | b386407dbbedb495fcdc651a439c918eff9fd5a3 (diff) |
Added basic HID descriptors.
-rw-r--r-- | usb/hid.h | 227 |
1 files changed, 227 insertions, 0 deletions
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 <typename T> +struct HID_Item { + uint8_t tag; + T data; +} __attribute__((packed)); + +template <> +struct HID_Item<void> { + uint8_t tag; +} __attribute__((packed)); + +constexpr HID_Item<void> hid_item(uint8_t tag) { + return {tag}; +} + +template <typename T> +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 <typename T> +constexpr HID_Item<T> hid_item(uint8_t tag, T data) { + return HID_Item<T>{uint8_t(tag | hid_item_data_size<T>()), data}; +} + +namespace UsagePage { + enum _8 : uint8_t { + Undefined, + Desktop, + Simulation, + VR, + Sport, + Game, + Generic, + Keyboard, + LED, + Button, + Ordinal, + }; +} + +constexpr HID_Item<UsagePage::_8> usage_page(UsagePage::_8 page) { + return hid_item(0x04, page); +} + +constexpr HID_Item<uint16_t> 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<DesktopUsage::_8> usage(DesktopUsage::_8 usage) { + return hid_item(0x08, usage); +} + +constexpr HID_Item<uint16_t> usage(uint16_t usage) { + return hid_item(0x08, usage); +} + +template <typename... R> +constexpr auto collection(Collection type, R... r) -> decltype(pack(HID_Item<Collection>(), r..., HID_Item<void>())) { + return pack(hid_item(0xa0, type), r..., hid_item(0xc0)); +} + +constexpr HID_Item<int16_t> usage_minimum(int16_t x) { + return hid_item(0x18, x); +} + +constexpr HID_Item<int16_t> usage_maximum(int16_t x) { + return hid_item(0x28, x); +} + +constexpr HID_Item<int32_t> logical_minimum(int32_t x) { + return hid_item(0x14, x); +} + +constexpr HID_Item<int32_t> logical_maximum(int32_t x) { + return hid_item(0x24, x); +} + +constexpr HID_Item<uint8_t> report_count(uint8_t x) { + return hid_item(0x94, x); +} + +constexpr HID_Item<uint8_t> report_size(uint8_t x) { + return hid_item(0x74, x); +} + +constexpr HID_Item<uint8_t> input(uint8_t x) { + return hid_item(0x80, x); +} + +constexpr HID_Item<uint8_t> output(uint8_t x) { + return hid_item(0x90, x); +} + +constexpr HID_Item<uint8_t> feature(uint8_t x) { + return hid_item(0xb0, x); +} + +constexpr HID_Item<uint8_t> report_id(uint8_t id) { + return hid_item(0x84, id); +} + +template <typename... R> +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 |