diff options
| author | 2016-03-18 22:27:36 +0200 | |
|---|---|---|
| committer | 2016-03-22 18:35:03 +0200 | |
| commit | db151efd0a50aa904a3021c45266f65355f6b4a7 (patch) | |
| tree | 15b8142fb8a996dccc5e85799fb0c972f3ef758b | |
| parent | Merge pull request #1543 from lioncash/zero (diff) | |
| download | yuzu-db151efd0a50aa904a3021c45266f65355f6b4a7.tar.gz yuzu-db151efd0a50aa904a3021c45266f65355f6b4a7.tar.xz yuzu-db151efd0a50aa904a3021c45266f65355f6b4a7.zip | |
implement accel and gyro backend
Diffstat (limited to '')
| -rw-r--r-- | src/common/emu_window.h | 48 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 93 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.h | 66 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid_spvr.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid_user.cpp | 20 |
5 files changed, 224 insertions, 23 deletions
diff --git a/src/common/emu_window.h b/src/common/emu_window.h index a0ae4c9fa..b6b7bfd26 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h | |||
| @@ -121,6 +121,54 @@ public: | |||
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | /** | 123 | /** |
| 124 | * Gets the current accelerometer state (acceleration along each three axis). | ||
| 125 | * Axis explained: | ||
| 126 | * +x is the same direction as LEFT on D-pad. | ||
| 127 | * +y is normal to the touch screen, pointing outward. | ||
| 128 | * +z is the same direction as UP on D-pad. | ||
| 129 | * Units: | ||
| 130 | * 1 unit of return value = 1/512 g (measured by hw test), | ||
| 131 | * where g is the gravitational acceleration (9.8 m/sec2). | ||
| 132 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 133 | * @todo Implement accelerometer input in front-end. | ||
| 134 | * @return std::tuple of (x, y, z) | ||
| 135 | */ | ||
| 136 | std::tuple<s16, s16, s16> GetAccelerometerState() const { | ||
| 137 | // stubbed | ||
| 138 | return std::make_tuple(0, -512, 0); | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Gets the current gyroscope state (angular rates about each three axis). | ||
| 143 | * Axis explained: | ||
| 144 | * +x is the same direction as LEFT on D-pad. | ||
| 145 | * +y is normal to the touch screen, pointing outward. | ||
| 146 | * +z is the same direction as UP on D-pad. | ||
| 147 | * Orientation is determined by right-hand rule. | ||
| 148 | * Units: | ||
| 149 | * 1 unit of return value = (1/coef) deg/sec, | ||
| 150 | * where coef is the return value of GetGyroscopeRawToDpsCoefficient(). | ||
| 151 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 152 | * @todo Implement gyroscope input in front-end. | ||
| 153 | * @return std::tuple of (x, y, z) | ||
| 154 | */ | ||
| 155 | std::tuple<s16, s16, s16> GetGyroscopeState() const { | ||
| 156 | // stubbed | ||
| 157 | return std::make_tuple(0, 0, 0); | ||
| 158 | } | ||
| 159 | |||
| 160 | /** | ||
| 161 | * Gets the coefficient for units conversion of gyroscope state. | ||
| 162 | * The conversion formula is r = coefficient * v, | ||
| 163 | * where v is angular rate in deg/sec, | ||
| 164 | * and r is the gyroscope state. | ||
| 165 | * @return float-type coefficient | ||
| 166 | */ | ||
| 167 | f32 GetGyroscopeRawToDpsCoefficient() const { | ||
| 168 | return 14.375f; // taken from hw test, and gyroscope's document | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 124 | * Returns currently active configuration. | 172 | * Returns currently active configuration. |
| 125 | * @note Accesses to the returned object need not be consistent because it may be modified in another thread | 173 | * @note Accesses to the returned object need not be consistent because it may be modified in another thread |
| 126 | */ | 174 | */ |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index cb4fd38e2..56bf89fa8 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -33,6 +33,11 @@ static Kernel::SharedPtr<Kernel::Event> event_debug_pad; | |||
| 33 | 33 | ||
| 34 | static u32 next_pad_index; | 34 | static u32 next_pad_index; |
| 35 | static u32 next_touch_index; | 35 | static u32 next_touch_index; |
| 36 | static u32 next_accelerometer_index; | ||
| 37 | static u32 next_gyroscope_index; | ||
| 38 | |||
| 39 | static int enable_accelerometer_count = 0; // positive means enabled | ||
| 40 | static int enable_gyroscope_count = 0; // positive means enabled | ||
| 36 | 41 | ||
| 37 | const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{ | 42 | const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{ |
| 38 | Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, | 43 | Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, |
| @@ -120,6 +125,58 @@ void Update() { | |||
| 120 | // Signal both handles when there's an update to Pad or touch | 125 | // Signal both handles when there's an update to Pad or touch |
| 121 | event_pad_or_touch_1->Signal(); | 126 | event_pad_or_touch_1->Signal(); |
| 122 | event_pad_or_touch_2->Signal(); | 127 | event_pad_or_touch_2->Signal(); |
| 128 | |||
| 129 | // Update accelerometer | ||
| 130 | if (enable_accelerometer_count > 0) { | ||
| 131 | mem->accelerometer.index = next_accelerometer_index; | ||
| 132 | next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size(); | ||
| 133 | |||
| 134 | AccelerometerDataEntry& accelerometer_entry = mem->accelerometer.entries[mem->accelerometer.index]; | ||
| 135 | std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) | ||
| 136 | = VideoCore::g_emu_window->GetAccelerometerState(); | ||
| 137 | |||
| 138 | // Make up "raw" entry | ||
| 139 | // TODO(wwylele): | ||
| 140 | // From hardware testing, the raw_entry values are approximately, | ||
| 141 | // but not exactly, as twice as corresponding entries (or with a minus sign). | ||
| 142 | // It may caused by system calibration to the accelerometer. | ||
| 143 | // Figure out how it works, or, if no game reads raw_entry, | ||
| 144 | // the following three lines can be removed and leave raw_entry unimplemented. | ||
| 145 | mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x; | ||
| 146 | mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y; | ||
| 147 | mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z; | ||
| 148 | |||
| 149 | // If we just updated index 0, provide a new timestamp | ||
| 150 | if (mem->accelerometer.index == 0) { | ||
| 151 | mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks; | ||
| 152 | mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks(); | ||
| 153 | } | ||
| 154 | |||
| 155 | event_accelerometer->Signal(); | ||
| 156 | } | ||
| 157 | |||
| 158 | // Update gyroscope | ||
| 159 | if (enable_gyroscope_count > 0) { | ||
| 160 | mem->gyroscope.index = next_gyroscope_index; | ||
| 161 | next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); | ||
| 162 | |||
| 163 | GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index]; | ||
| 164 | std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) | ||
| 165 | = VideoCore::g_emu_window->GetGyroscopeState(); | ||
| 166 | |||
| 167 | // Make up "raw" entry | ||
| 168 | mem->gyroscope.raw_entry.x = gyroscope_entry.x; | ||
| 169 | mem->gyroscope.raw_entry.z = -gyroscope_entry.y; | ||
| 170 | mem->gyroscope.raw_entry.y = gyroscope_entry.z; | ||
| 171 | |||
| 172 | // If we just updated index 0, provide a new timestamp | ||
| 173 | if (mem->gyroscope.index == 0) { | ||
| 174 | mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks; | ||
| 175 | mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks(); | ||
| 176 | } | ||
| 177 | |||
| 178 | event_gyroscope->Signal(); | ||
| 179 | } | ||
| 123 | } | 180 | } |
| 124 | 181 | ||
| 125 | void GetIPCHandles(Service::Interface* self) { | 182 | void GetIPCHandles(Service::Interface* self) { |
| @@ -139,40 +196,70 @@ void GetIPCHandles(Service::Interface* self) { | |||
| 139 | void EnableAccelerometer(Service::Interface* self) { | 196 | void EnableAccelerometer(Service::Interface* self) { |
| 140 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 197 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 141 | 198 | ||
| 199 | ++enable_accelerometer_count; | ||
| 142 | event_accelerometer->Signal(); | 200 | event_accelerometer->Signal(); |
| 143 | 201 | ||
| 144 | cmd_buff[1] = RESULT_SUCCESS.raw; | 202 | cmd_buff[1] = RESULT_SUCCESS.raw; |
| 145 | 203 | ||
| 146 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 204 | LOG_DEBUG(Service_HID, "called"); |
| 147 | } | 205 | } |
| 148 | 206 | ||
| 149 | void DisableAccelerometer(Service::Interface* self) { | 207 | void DisableAccelerometer(Service::Interface* self) { |
| 150 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 208 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 151 | 209 | ||
| 210 | --enable_accelerometer_count; | ||
| 152 | event_accelerometer->Signal(); | 211 | event_accelerometer->Signal(); |
| 153 | 212 | ||
| 154 | cmd_buff[1] = RESULT_SUCCESS.raw; | 213 | cmd_buff[1] = RESULT_SUCCESS.raw; |
| 155 | 214 | ||
| 156 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 215 | LOG_DEBUG(Service_HID, "called"); |
| 157 | } | 216 | } |
| 158 | 217 | ||
| 159 | void EnableGyroscopeLow(Service::Interface* self) { | 218 | void EnableGyroscopeLow(Service::Interface* self) { |
| 160 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 219 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 161 | 220 | ||
| 221 | ++enable_gyroscope_count; | ||
| 162 | event_gyroscope->Signal(); | 222 | event_gyroscope->Signal(); |
| 163 | 223 | ||
| 164 | cmd_buff[1] = RESULT_SUCCESS.raw; | 224 | cmd_buff[1] = RESULT_SUCCESS.raw; |
| 165 | 225 | ||
| 166 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 226 | LOG_DEBUG(Service_HID, "called"); |
| 167 | } | 227 | } |
| 168 | 228 | ||
| 169 | void DisableGyroscopeLow(Service::Interface* self) { | 229 | void DisableGyroscopeLow(Service::Interface* self) { |
| 170 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 230 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 171 | 231 | ||
| 232 | --enable_gyroscope_count; | ||
| 172 | event_gyroscope->Signal(); | 233 | event_gyroscope->Signal(); |
| 173 | 234 | ||
| 174 | cmd_buff[1] = RESULT_SUCCESS.raw; | 235 | cmd_buff[1] = RESULT_SUCCESS.raw; |
| 175 | 236 | ||
| 237 | LOG_DEBUG(Service_HID, "called"); | ||
| 238 | } | ||
| 239 | |||
| 240 | void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self) { | ||
| 241 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 242 | |||
| 243 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 244 | |||
| 245 | f32 coef = VideoCore::g_emu_window->GetGyroscopeRawToDpsCoefficient(); | ||
| 246 | memcpy(&cmd_buff[2], &coef, 4); | ||
| 247 | } | ||
| 248 | |||
| 249 | void GetGyroscopeLowCalibrateParam(Service::Interface* self) { | ||
| 250 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 251 | |||
| 252 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 253 | |||
| 254 | // currently don't understand the meaning of return value, | ||
| 255 | // so stubbed these with value from a real console. | ||
| 256 | // TODO(wwylele): implement this correctly | ||
| 257 | cmd_buff[2] = 0x19DDFFDC; | ||
| 258 | cmd_buff[3] = 0x0002E5DA; | ||
| 259 | cmd_buff[4] = 0xE5CE1A2D; | ||
| 260 | cmd_buff[5] = 0x19C6FFF3; | ||
| 261 | cmd_buff[6] = 0x001CE61E; | ||
| 262 | |||
| 176 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 263 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 177 | } | 264 | } |
| 178 | 265 | ||
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 517f4f2ae..ebe137525 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -78,6 +78,24 @@ struct TouchDataEntry { | |||
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | /** | 80 | /** |
| 81 | * Structure of a single entry of accelerometer state history within HID shared memory | ||
| 82 | */ | ||
| 83 | struct AccelerometerDataEntry { | ||
| 84 | s16 x; | ||
| 85 | s16 y; | ||
| 86 | s16 z; | ||
| 87 | }; | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Structure of a single entry of gyroscope state history within HID shared memory | ||
| 91 | */ | ||
| 92 | struct GyroscopeDataEntry { | ||
| 93 | s16 x; | ||
| 94 | s16 y; | ||
| 95 | s16 z; | ||
| 96 | }; | ||
| 97 | |||
| 98 | /** | ||
| 81 | * Structure of data stored in HID shared memory | 99 | * Structure of data stored in HID shared memory |
| 82 | */ | 100 | */ |
| 83 | struct SharedMem { | 101 | struct SharedMem { |
| @@ -112,6 +130,34 @@ struct SharedMem { | |||
| 112 | 130 | ||
| 113 | std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates | 131 | std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates |
| 114 | } touch; | 132 | } touch; |
| 133 | |||
| 134 | /// Accelerometer data | ||
| 135 | struct { | ||
| 136 | s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 | ||
| 137 | s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` | ||
| 138 | u32 index; ///< Index of the last updated accelerometer entry | ||
| 139 | |||
| 140 | INSERT_PADDING_WORDS(0x1); | ||
| 141 | |||
| 142 | AccelerometerDataEntry raw_entry; | ||
| 143 | INSERT_PADDING_BYTES(2); | ||
| 144 | |||
| 145 | std::array<AccelerometerDataEntry, 8> entries; | ||
| 146 | } accelerometer; | ||
| 147 | |||
| 148 | /// Gyroscope data | ||
| 149 | struct { | ||
| 150 | s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 | ||
| 151 | s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` | ||
| 152 | u32 index; ///< Index of the last updated accelerometer entry | ||
| 153 | |||
| 154 | INSERT_PADDING_WORDS(0x1); | ||
| 155 | |||
| 156 | GyroscopeDataEntry raw_entry; | ||
| 157 | INSERT_PADDING_BYTES(2); | ||
| 158 | |||
| 159 | std::array<GyroscopeDataEntry, 32> entries; | ||
| 160 | } gyroscope; | ||
| 115 | }; | 161 | }; |
| 116 | 162 | ||
| 117 | // TODO: MSVC does not support using offsetof() on non-static data members even though this | 163 | // TODO: MSVC does not support using offsetof() on non-static data members even though this |
| @@ -222,6 +268,26 @@ void DisableGyroscopeLow(Interface* self); | |||
| 222 | */ | 268 | */ |
| 223 | void GetSoundVolume(Interface* self); | 269 | void GetSoundVolume(Interface* self); |
| 224 | 270 | ||
| 271 | /** | ||
| 272 | * HID::GetGyroscopeLowRawToDpsCoefficient service function | ||
| 273 | * Inputs: | ||
| 274 | * None | ||
| 275 | * Outputs: | ||
| 276 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 277 | * 2 : float output value | ||
| 278 | */ | ||
| 279 | void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self); | ||
| 280 | |||
| 281 | /** | ||
| 282 | * HID::GetGyroscopeLowCalibrateParam service function | ||
| 283 | * Inputs: | ||
| 284 | * None | ||
| 285 | * Outputs: | ||
| 286 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 287 | * 2~6 : CalibrateParam? | ||
| 288 | */ | ||
| 289 | void GetGyroscopeLowCalibrateParam(Service::Interface* self); | ||
| 290 | |||
| 225 | /// Checks for user input updates | 291 | /// Checks for user input updates |
| 226 | void Update(); | 292 | void Update(); |
| 227 | 293 | ||
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index c50f597eb..046e65b11 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp | |||
| @@ -9,16 +9,16 @@ namespace Service { | |||
| 9 | namespace HID { | 9 | namespace HID { |
| 10 | 10 | ||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | 11 | const Interface::FunctionInfo FunctionTable[] = { |
| 12 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, | 12 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, |
| 13 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, | 13 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, |
| 14 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, | 14 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, |
| 15 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, | 15 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, |
| 16 | {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, | 16 | {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, |
| 17 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, | 17 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, |
| 18 | {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"}, | 18 | {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"}, |
| 19 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, | 19 | {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"}, |
| 20 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, | 20 | {0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"}, |
| 21 | {0x00170000, GetSoundVolume, "GetSoundVolume"}, | 21 | {0x00170000, GetSoundVolume, "GetSoundVolume"}, |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | HID_SPVR_Interface::HID_SPVR_Interface() { | 24 | HID_SPVR_Interface::HID_SPVR_Interface() { |
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index bbdde2abb..bb157b83d 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp | |||
| @@ -9,16 +9,16 @@ namespace Service { | |||
| 9 | namespace HID { | 9 | namespace HID { |
| 10 | 10 | ||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | 11 | const Interface::FunctionInfo FunctionTable[] = { |
| 12 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, | 12 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, |
| 13 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, | 13 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, |
| 14 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, | 14 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, |
| 15 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, | 15 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, |
| 16 | {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, | 16 | {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, |
| 17 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, | 17 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, |
| 18 | {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"}, | 18 | {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"}, |
| 19 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, | 19 | {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"}, |
| 20 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, | 20 | {0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"}, |
| 21 | {0x00170000, GetSoundVolume, "GetSoundVolume"}, | 21 | {0x00170000, GetSoundVolume, "GetSoundVolume"}, |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | HID_U_Interface::HID_U_Interface() { | 24 | HID_U_Interface::HID_U_Interface() { |