The Pedigree Project 0.1
HidUtils.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "modules/drivers/common/hid/HidUtils.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/machine/HidInputManager.h"
23#include "pedigree/kernel/machine/InputManager.h"
24
25#include "modules/drivers/common/hid/HidUsages.h"
26
27Spinlock HidUtils::InputState::m_Lock;
28HidUtils::InputState* HidUtils::InputState::m_pInputs = nullptr;
29
30HidUtils::InputState::InputState()
31 : m_pNext(nullptr), m_Keys{}, m_MouseButtons(0), m_JoystickButtons(0) {
32 LockGuard<Spinlock> guard(m_Lock);
33 m_pNext = m_pInputs;
34 m_pInputs = this;
35}
36
37HidUtils::InputState::~InputState() {
38 LockGuard<Spinlock> guard(m_Lock);
39 for (size_t key = 0; key < 256; ++key) {
40 if (m_Keys[key / 64] & (uint64_t{1} << (key % 64))) {
42 }
43 }
44 InputState** input = &m_pInputs;
45 while (*input != this) {
46 input = &(*input)->m_pNext;
47 }
48 *input = m_pNext;
49 if (m_MouseButtons) {
50 InputManager::instance().mouseUpdate(0, 0, 0, buttons(Mouse));
51 }
52 if (m_JoystickButtons) {
53 InputManager::instance().joystickUpdate(0, 0, 0, buttons(Joystick));
54 }
55}
56
57uint32_t HidUtils::InputState::buttons(HidDeviceType deviceType) {
58 uint32_t bitmap = 0;
59 for (InputState* input = m_pInputs; input; input = input->m_pNext) {
60 bitmap |= deviceType == Mouse ? input->m_MouseButtons : input->m_JoystickButtons;
61 }
62 return bitmap;
63}
64
65uint64_t HidUtils::getBufferField(uint8_t* pBuffer, size_t nStart, size_t nLength) {
66 if (nLength > 64)
67 return 0;
68 uint64_t value = 0;
69 for (size_t i = 0; i < nLength; ++i)
70 value |= uint64_t{(pBuffer[(nStart + i) / 8] >> ((nStart + i) % 8)) & 1U} << i;
71 return value;
72}
73
74void HidUtils::fixNegativeMinimum(int64_t& nMin, int64_t nMax) {
75 // Ignore the call if nMax is larger than nMin (no sign bit set in nMin)
76 if (nMax > nMin)
77 return;
78
79 // Check for all possible sign bits
80 // NOTE this was "nMin = -((1 << bitNum) - nMin)" originally, now may seem
81 // confusing
82 if (nMin < (1LL << 8) && nMin & (1LL << 7)) // Signed 8-bit
83 nMin -= 1LL << 8; // Turn nMin negative
84 else if (nMin < (1LL << 16) && nMin & (1LL << 15)) // Signed 16-bit
85 nMin -= 1LL << 16; // Turn nMin negative
86 else if (nMin < (1LL << 32) && nMin & (1LL << 31)) // Signed 32-bit
87 nMin -= 1LL << 32; // Turn nMin negative
88}
89
90void HidUtils::fixNegativeValue(int64_t nMin, int64_t nMax, int64_t& nValue) {
91 // Ignore the call if nMin is not negative at all
92 if (nMin >= 0)
93 return;
94
95 // Ignore the call if nMax is larger than nValue (no sign bit set in nValue)
96 if (nMax > nValue)
97 return;
98
99 // Check for all possible sign bits
100 if (nMin > -(1LL << 8) && nValue < (1LL << 8) && nValue & (1LL << 7)) // Signed 8-bit
101 nValue -= 1LL << 8; // Turn nValue negative
102 else if (nMin > -(1LL << 16) && nValue < (1LL << 16) && nValue & (1LL << 15)) // Signed 16-bit
103 nValue -= 1LL << 16; // Turn nValue negative
104 else if (nMin > -(1LL << 32) && nValue < (1LL << 32) && nValue & (1LL << 31)) // Signed 32-bit
105 nValue -= 1LL << 32; // Turn nValue negative
106}
107
108void HidUtils::sendInputToManager(HidDeviceType deviceType, uint16_t nUsagePage, uint16_t nUsage,
109 int64_t nRelativeValue, InputState& state) {
110 LockGuard<Spinlock> guard(InputState::m_Lock);
111
112 // Is this a key on a keyboard/keypad?
113 if ((deviceType == Keyboard) && (nUsagePage == HidUsagePages::Keyboard)) {
114 if (!nUsage || nUsage > 255) {
115 return;
116 }
117 const uint64_t bit = uint64_t{1} << (nUsage % 64);
118 if (nRelativeValue > 0) {
119 state.m_Keys[nUsage / 64] |= bit;
120 HidInputManager::instance().keyDown(nUsage, &state);
121 } else {
122 state.m_Keys[nUsage / 64] &= ~bit;
123 HidInputManager::instance().keyUp(nUsage, &state);
124 }
125 }
126
127 const uint32_t mouseButtons = InputState::buttons(Mouse);
128 const uint32_t joystickButtons = InputState::buttons(Joystick);
129 // Is this an axis on a mouse?
130 if ((deviceType == Mouse) && (nUsagePage == HidUsagePages::GenericDesktop)) {
131 if (nUsage == HidUsages::X)
132 InputManager::instance().mouseUpdate(nRelativeValue, 0, 0, mouseButtons);
133 if (nUsage == HidUsages::Y)
134 InputManager::instance().mouseUpdate(0, nRelativeValue, 0, mouseButtons);
135 if (nUsage == HidUsages::Wheel)
136 InputManager::instance().mouseUpdate(0, 0, nRelativeValue, mouseButtons);
137 }
138
139 // Is this an axis on a joystick?
140 if ((deviceType == Joystick) && (nUsagePage == HidUsagePages::GenericDesktop)) {
141 if (nUsage == HidUsages::X)
142 InputManager::instance().joystickUpdate(nRelativeValue, 0, 0, joystickButtons);
143 if (nUsage == HidUsages::Y)
144 InputManager::instance().joystickUpdate(0, nRelativeValue, 0, joystickButtons);
145 if (nUsage == HidUsages::Z)
146 InputManager::instance().joystickUpdate(0, 0, nRelativeValue, joystickButtons);
147 }
148
149 // Is this a button on a mouse?
150 if ((deviceType == Mouse) && (nUsagePage == HidUsagePages::Button)) {
151 if (!nUsage || nUsage > 32) {
152 return;
153 }
154 // Set/unset the bit in the bitmap
155 if (nRelativeValue > 0) {
156 state.m_MouseButtons |= uint32_t{1} << (nUsage - 1);
157 } else {
158 state.m_MouseButtons &= ~(uint32_t{1} << (nUsage - 1));
159 }
160
161 // Send the new bitmap to the input manager
162 InputManager::instance().mouseUpdate(0, 0, 0, InputState::buttons(Mouse));
163 }
164
165 // Is this a button on a joystick?
166 if ((deviceType == Joystick) && (nUsagePage == HidUsagePages::Button)) {
167 if (!nUsage || nUsage > 32) {
168 return;
169 }
170 // Set/unset the bit in the bitmap
171 if (nRelativeValue > 0) {
172 state.m_JoystickButtons |= uint32_t{1} << (nUsage - 1);
173 } else {
174 state.m_JoystickButtons &= ~(uint32_t{1} << (nUsage - 1));
175 }
176
177 // Send the new bitmap to the input manager
178 InputManager::instance().joystickUpdate(0, 0, 0, InputState::buttons(Joystick));
179 }
180}
void keyDown(uint8_t keyCode, const void *source=nullptr)
Called when a key transitions to the "down" state.
static HidInputManager & instance()
Singleton design.
void keyUp(uint8_t keyCode, const void *source=nullptr)
Called when a key transitions to the "up" state.
Held input belongs to a report instance and is retired with that instance.
Definition HidUtils.h:32
static InputManager & instance()
Singleton design.
void mouseUpdate(ssize_t relX, ssize_t relY, ssize_t relZ, uint32_t buttonBitmap)
Called whenever mouse input comes in.
void joystickUpdate(ssize_t relX, ssize_t relY, ssize_t relZ, uint32_t buttonBitmap)
Called whenever joystick input comes in.
void fixNegativeMinimum(int64_t &nMin, int64_t nMax)
Converts.
Definition HidUtils.cc:74
uint64_t getBufferField(uint8_t *pBuffer, size_t nStart, size_t nLength)
Retrieves a field in a buffer.
Definition HidUtils.cc:65
void fixNegativeValue(int64_t nMin, int64_t nMax, int64_t &nValue)
Converts.
Definition HidUtils.cc:90
void sendInputToManager(HidDeviceType deviceType, uint16_t nUsagePage, uint16_t nUsage, int64_t nRelativeValue, InputState &state)
Sends the input to the right handler in HidInputManager or InputManager.
Definition HidUtils.cc:108