kvm-guest-drivers-windows

Форк
0
328 строк · 12.1 Кб
1
/*
2
 * Joystick specific HID functionality
3
 *
4
 * Copyright (c) 2016-2017 Red Hat, Inc.
5
 *
6
 * Author(s):
7
 *  Ladi Prosek <lprosek@redhat.com>
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met :
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and / or other materials provided with the distribution.
17
 * 3. Neither the names of the copyright holders nor the names of their contributors
18
 *    may be used to endorse or promote products derived from this software
19
 *    without specific prior written permission.
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32

33
#include "precomp.h"
34
#include "vioinput.h"
35
#include "Hid.h"
36

37
#if defined(EVENT_TRACING)
38
#include "HidJoystick.tmh"
39
#endif
40

41
// initial length of the axis map (will grow as needed)
42
#define AXIS_MAP_INITIAL_LENGTH 6
43

44
typedef struct _tagInputClassJoystick
45
{
46
    INPUT_CLASS_COMMON Common;
47

48
    // the joystick HID report is laid out as follows:
49
    // offset 0
50
    // * report ID
51
    // offset 1
52
    // * axes; four bytes per axis, mapping in pAxisMap
53
    // offset 1 + cbAxisLen
54
    // * buttons; one bit per button followed by padding to the nearest whole byte
55

56
    // number of buttons supported by the HID report
57
    ULONG  uNumOfButtons;
58
    // length of axis data
59
    SIZE_T cbAxisLen;
60
    // mapping from EVDEV axis codes to HID axis offsets
61
    PULONG pAxisMap;
62
} INPUT_CLASS_JOYSTICK, *PINPUT_CLASS_JOYSTICK;
63

64
static NTSTATUS
65
HIDJoystickEventToReport(
66
    PINPUT_CLASS_COMMON pClass,
67
    PVIRTIO_INPUT_EVENT pEvent)
68
{
69
    PUCHAR pReport = pClass->pHidReport;
70
    PINPUT_CLASS_JOYSTICK pJoystickDesc = (PINPUT_CLASS_JOYSTICK)pClass;
71

72
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> %s\n", __FUNCTION__);
73

74
    pReport[HID_REPORT_ID_OFFSET] = pClass->uReportID;
75
    switch (pEvent->type)
76
    {
77
    case EV_ABS:
78
        if (pJoystickDesc->pAxisMap)
79
        {
80
            PULONG pMap;
81
            for (pMap = pJoystickDesc->pAxisMap; pMap[0] != (ULONG)-1; pMap += 2)
82
            {
83
                if (pMap[0] == ((pEvent->type << 16) | pEvent->code))
84
                {
85
                    // 4 bytes per absolute axis
86
                    PULONG pAxisPtr = (PULONG)&pReport[HID_REPORT_DATA_OFFSET + pMap[1]];
87
                    *pAxisPtr = pEvent->value;
88
                    pClass->bDirty = TRUE;
89
                }
90
            }
91
        }
92
        break;
93
    case EV_KEY:
94
        if (pEvent->code >= BTN_JOYSTICK && pEvent->code < BTN_GAMEPAD)
95
        {
96
            USHORT uButton = pEvent->code - BTN_JOYSTICK;
97
            if (uButton < pJoystickDesc->uNumOfButtons)
98
            {
99
                SIZE_T cbOffset = pJoystickDesc->cbAxisLen + (uButton / 8);
100
                UCHAR uBit = 1 << (uButton % 8);
101
                if (pEvent->value)
102
                {
103
                    pReport[HID_REPORT_DATA_OFFSET + cbOffset] |= uBit;
104
                }
105
                else
106
                {
107
                    pReport[HID_REPORT_DATA_OFFSET + cbOffset] &= ~uBit;
108
                }
109
                pClass->bDirty = TRUE;
110
            }
111
        }
112
        break;
113
    }
114

115
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %s\n", __FUNCTION__);
116
    return STATUS_SUCCESS;
117
}
118

119
static VOID
120
HIDJoystickCleanup(
121
    PINPUT_CLASS_COMMON pClass)
122
{
123
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
124

125
    PINPUT_CLASS_JOYSTICK pJoystickDesc = (PINPUT_CLASS_JOYSTICK)pClass;
126
    VIOInputFree(&pJoystickDesc->pAxisMap);
127

128
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__);
129
}
130

131
static VOID
132
HIDJoystickAxisMapAppend(
133
    PDYNAMIC_ARRAY pAxisMap,
134
    ULONG uCode,
135
    SIZE_T uAxisIndex)
136
{
137
    DynamicArrayAppend(pAxisMap, &uCode, sizeof(ULONG));
138
    DynamicArrayAppend(pAxisMap, &uAxisIndex, sizeof(ULONG));
139
}
140

141
NTSTATUS
142
HIDJoystickProbe(
143
    PINPUT_DEVICE pContext,
144
    PDYNAMIC_ARRAY pHidDesc,
145
    PVIRTIO_INPUT_CFG_DATA pAxes,
146
    PVIRTIO_INPUT_CFG_DATA pButtons)
147
{
148
    PINPUT_CLASS_JOYSTICK pJoystickDesc = NULL;
149
    NTSTATUS status = STATUS_SUCCESS;
150
    UCHAR i, uValue;
151
    SIZE_T cbButtonBytes;
152
    ULONG uNumOfAbsAxes = 0, uNumOfButtons = 0;
153
    DYNAMIC_ARRAY AxisMap = { NULL };
154

155
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
156

157
    for (i = 0; i < pButtons->size; i++)
158
    {
159
        UCHAR uNonButtons = 0;
160
        while (DecodeNextBit(&pButtons->u.bitmap[i], &uValue))
161
        {
162
            ULONG uButtonCode = uValue + 8 * i;
163
            if (uButtonCode >= BTN_JOYSTICK && uButtonCode < BTN_GAMEPAD)
164
            {
165
                // individual joystick button functions are not specified in the HID report,
166
                // only their count is; the max button code we find will determine the count
167
                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got button %d\n", uButtonCode);
168
                uNumOfButtons = max(uNumOfButtons, uButtonCode - BTN_JOYSTICK + 1);
169
            }
170
            else
171
            {
172
                // not a joystick button, put it back and let other devices claim it
173
                uNonButtons |= (1 << uValue);
174
            }
175
        }
176
        pButtons->u.bitmap[i] = uNonButtons;
177
    }
178

179
    if (uNumOfButtons == 0)
180
    {
181
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Joystick buttons not found\n");
182
        goto Exit;
183
    }
184

185
    // allocate and initialize pJoystickDesc
186
    pJoystickDesc = VIOInputAlloc(sizeof(INPUT_CLASS_JOYSTICK));
187
    if (pJoystickDesc == NULL)
188
    {
189
        status = STATUS_INSUFFICIENT_RESOURCES;
190
        goto Exit;
191
    }
192
    pJoystickDesc->Common.EventToReportFunc = HIDJoystickEventToReport;
193
    pJoystickDesc->Common.CleanupFunc = HIDJoystickCleanup;
194
    pJoystickDesc->Common.uReportID = (UCHAR)(pContext->uNumOfClasses + 1);
195
    pJoystickDesc->uNumOfButtons = uNumOfButtons;
196

197
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_GENERIC);
198
    HIDAppend2(pHidDesc, HID_TAG_USAGE, HID_USAGE_GENERIC_JOYSTICK);
199
    HIDAppend2(pHidDesc, HID_TAG_COLLECTION, HID_COLLECTION_APPLICATION);
200

201
    HIDAppend2(pHidDesc, HID_TAG_REPORT_ID, pJoystickDesc->Common.uReportID);
202

203
    // describe axes
204
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_GENERIC);
205
    DynamicArrayReserve(&AxisMap, AXIS_MAP_INITIAL_LENGTH * 2 * sizeof(ULONG));
206

207
    for (i = 0; i < pAxes->size; i++)
208
    {
209
        UCHAR uNonAxes = 0;
210
        while (DecodeNextBit(&pAxes->u.bitmap[i], &uValue))
211
        {
212
            USHORT uAbsCode = uValue + 8 * i;
213
            BOOLEAN bSimulationPage = FALSE;
214
            ULONG uAxisCode = 0;
215

216
            switch (uAbsCode)
217
            {
218
            case ABS_X: uAxisCode = HID_USAGE_GENERIC_X; break;
219
            case ABS_Y: uAxisCode = HID_USAGE_GENERIC_Y; break;
220
            case ABS_Z: uAxisCode = HID_USAGE_GENERIC_Z; break;
221
            case ABS_RX: uAxisCode = HID_USAGE_GENERIC_RX; break;
222
            case ABS_RY: uAxisCode = HID_USAGE_GENERIC_RY; break;
223
            case ABS_RZ: uAxisCode = HID_USAGE_GENERIC_RZ; break;
224
            case ABS_TILT_X: uAxisCode = HID_USAGE_GENERIC_VX; break;
225
            case ABS_TILT_Y: uAxisCode = HID_USAGE_GENERIC_VY; break;
226
            case ABS_MISC: uAxisCode = HID_USAGE_GENERIC_SLIDER; break;
227
            case ABS_THROTTLE: bSimulationPage = TRUE; uAxisCode = HID_USAGE_SIMULATION_THROTTLE; break;
228
            case ABS_RUDDER:   bSimulationPage = TRUE; uAxisCode = HID_USAGE_SIMULATION_RUDDER; break;
229
            case ABS_BRAKE:    bSimulationPage = TRUE; uAxisCode = HID_USAGE_SIMULATION_BRAKE; break;
230
            case ABS_WHEEL:    bSimulationPage = TRUE; uAxisCode = HID_USAGE_SIMULATION_STEERING; break;
231
            case ABS_GAS:      bSimulationPage = TRUE; uAxisCode = HID_USAGE_SIMULATION_ACCELERATOR; break;
232
            }
233

234
            if (uAxisCode != 0)
235
            {
236
                struct virtio_input_absinfo AbsInfo;
237
                GetAbsAxisInfo(pContext, uAbsCode, &AbsInfo);
238

239
                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got joystick axis %d, min %d, max %d\n",
240
                            uAxisCode, AbsInfo.min, AbsInfo.max);
241

242
                // some of the supported axes are on the generic page, some on the simulation page
243
                if (bSimulationPage)
244
                {
245
                    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_SIMULATION);
246
                }
247
                else
248
                {
249
                    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_GENERIC);
250
                }
251
                HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, AbsInfo.min);
252
                HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, AbsInfo.max);
253

254
                // for simplicity always use 4-byte fields in the report
255
                HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x20);
256
                HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
257

258
                HIDAppend2(pHidDesc, HID_TAG_USAGE, uAxisCode);
259
                HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE);
260

261
                // add mapping for this axis
262
                HIDJoystickAxisMapAppend(&AxisMap, (EV_ABS << 16) | uAbsCode, pJoystickDesc->cbAxisLen);
263
                pJoystickDesc->cbAxisLen += 4;
264
                uNumOfAbsAxes++;
265
            }
266
            else
267
            {
268
                uNonAxes |= (1 << uValue);
269
            }
270
        }
271
        pAxes->u.bitmap[i] = uNonAxes;
272
    }
273

274
    // finalize the axis map
275
    HIDJoystickAxisMapAppend(&AxisMap, (ULONG)-1, (ULONG)-1);
276
    pJoystickDesc->pAxisMap = DynamicArrayGet(&AxisMap, NULL);
277
    if (pJoystickDesc->pAxisMap == NULL)
278
    {
279
        status = STATUS_INSUFFICIENT_RESOURCES;
280
        goto Exit;
281
    }
282

283
    // one bit per button
284
    cbButtonBytes = (uNumOfButtons + 7) / 8;
285
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_BUTTON);
286
    HIDAppend2(pHidDesc, HID_TAG_USAGE_MINIMUM, 0x01);
287
    HIDAppend2(pHidDesc, HID_TAG_USAGE_MAXIMUM, uNumOfButtons);
288
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, 0x00);
289
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, 0x01);
290
    HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, uNumOfButtons);
291
    HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x01);
292
    HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE);
293

294
    // pad to the nearest whole byte
295
    if (uNumOfButtons % 8)
296
    {
297
        HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
298
        HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, (ULONG)(cbButtonBytes * 8) - uNumOfButtons);
299
        HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE | HID_DATA_FLAG_CONSTANT);
300
    }
301

302
    HIDAppend1(pHidDesc, HID_TAG_END_COLLECTION);
303

304
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
305
                "Created HID joystick report descriptor with %d axes and %d buttons\n",
306
                uNumOfAbsAxes,
307
                uNumOfButtons);
308

309
    // calculate the joystick HID report size
310
    pJoystickDesc->Common.cbHidReportSize =
311
        1ll +                 // report ID
312
        uNumOfAbsAxes * 4ll + // axes
313
        cbButtonBytes;      // buttons
314

315
    // register the joystick class
316
    status = RegisterClass(pContext, &pJoystickDesc->Common);
317

318
Exit:
319
    DynamicArrayDestroy(&AxisMap);
320
    if (!NT_SUCCESS(status) && pJoystickDesc != NULL)
321
    {
322
        pJoystickDesc->Common.CleanupFunc(&pJoystickDesc->Common);
323
        VIOInputFree(&pJoystickDesc);
324
    }
325

326
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s (%08x)\n", __FUNCTION__, status);
327
    return status;
328
}
329

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.