-
Notifications
You must be signed in to change notification settings - Fork 79
Expand file tree
/
Copy pathusb_interface_mouse.c
More file actions
222 lines (188 loc) · 7.82 KB
/
Copy pathusb_interface_mouse.c
File metadata and controls
222 lines (188 loc) · 7.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#include "usb_composite_device.h"
#include "usb_report_updater.h"
#include <string.h>
#include "event_scheduler.h"
#include "attributes.h"
#include "macros/status_buffer.h"
#ifdef __ZEPHYR__
#include "usb/usb_compatibility.h"
#endif
#include "usb_descriptors/usb_descriptor_mouse_report.h"
static usb_mouse_report_t usbMouseReports[2];
usb_hid_protocol_t usbMouseProtocol;
uint32_t UsbMouseActionCounter;
usb_mouse_report_t* ActiveUsbMouseReport = usbMouseReports;
static usb_mouse_report_t* GetInactiveUsbMouseReport(void)
{
return ActiveUsbMouseReport == usbMouseReports ? usbMouseReports+1 : usbMouseReports;
}
void UsbMouseResetActiveReport(void)
{
memset(ActiveUsbMouseReport, 0, USB_MOUSE_REPORT_LENGTH);
}
static void SwitchActiveUsbMouseReport(void)
{
ActiveUsbMouseReport = GetInactiveUsbMouseReport();
}
#ifndef __ZEPHYR__
static uint8_t usbMouseFeatBuffer[USB_MOUSE_FEAT_REPORT_LENGTH];
usb_hid_protocol_t UsbMouseGetProtocol(void)
{
return usbMouseProtocol;
}
usb_status_t UsbMouseAction(void)
{
if (!UsbCompositeDevice.attach) {
return kStatus_USB_Error; // The device is not attached
}
usb_status_t usb_status = USB_DeviceHidSend(
UsbCompositeDevice.mouseHandle, USB_MOUSE_ENDPOINT_INDEX,
(uint8_t *)ActiveUsbMouseReport, USB_MOUSE_REPORT_LENGTH);
if (usb_status == kStatus_USB_Success) {
UsbMouseActionCounter++;
SwitchActiveUsbMouseReport();
}
// latch the active protocol to avoid ISR <-> Thread race
usbMouseProtocol = ((usb_device_hid_struct_t*)UsbCompositeDevice.mouseHandle)->protocol;
return usb_status;
}
float VerticalScrollMultiplier(void)
{
return usbMouseFeatBuffer[0] & 0x01 ? USB_MOUSE_REPORT_DESCRIPTOR_MAX_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE : USB_MOUSE_REPORT_DESCRIPTOR_MIN_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE;
}
float HorizontalScrollMultiplier(void)
{
return usbMouseFeatBuffer[0] & 0x01 ? USB_MOUSE_REPORT_DESCRIPTOR_MAX_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE : USB_MOUSE_REPORT_DESCRIPTOR_MIN_RESOLUTION_MULTIPLIER_PHYSICAL_VALUE;
}
usb_status_t UsbMouseCallback(class_handle_t handle, uint32_t event, void *param)
{
usb_device_hid_struct_t *hidHandle = (usb_device_hid_struct_t *)handle;
usb_status_t error = kStatus_USB_InvalidRequest;
switch (event) {
case ((uint32_t)-kUSB_DeviceEventSetConfiguration):
Macros_ReportPrintf(NULL, "USB Mouse: Set Configuration -> 0");
usbMouseFeatBuffer[0] = 0;
error = kStatus_USB_Success;
break;
case ((uint32_t)-kUSB_DeviceEventSetInterface):
if (*(uint8_t*)param == 0) {
error = kStatus_USB_Success;
}
break;
case kUSB_DeviceHidEventSendResponse:
UsbReportUpdateSemaphore &= ~(1 << USB_MOUSE_INTERFACE_INDEX);
if (UsbCompositeDevice.attach) {
error = kStatus_USB_Success;
}
break;
case kUSB_DeviceHidEventGetReport: {
usb_device_hid_report_struct_t *report = (usb_device_hid_report_struct_t*)param;
if (report->reportId != 0) {
error = kStatus_USB_InvalidRequest;
} else if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_INPUT && report->reportLength <= USB_MOUSE_REPORT_LENGTH) {
report->reportBuffer = (void*)ActiveUsbMouseReport;
UsbMouseActionCounter++;
SwitchActiveUsbMouseReport();
error = kStatus_USB_Success;
} else if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_FEATURE) {
report->reportBuffer = usbMouseFeatBuffer;
report->reportLength = sizeof(usbMouseFeatBuffer);
error = kStatus_USB_Success;
} else {
error = kStatus_USB_InvalidRequest;
}
break;
}
case kUSB_DeviceHidEventSetReport: {
usb_device_hid_report_struct_t *report = (usb_device_hid_report_struct_t*)param;
if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_FEATURE && report->reportId == 0 && report->reportLength <= sizeof(usbMouseFeatBuffer)) {
// With a single resolution multiplier, this case will never be
// hit on Linux (for multiple resolution multipliers, one value
// will be missing, so would have to be inferred from the
// other(s)). But Windows does use this request properly, so it
// needs to be handled appropriately.
error = kStatus_USB_Success;
} else {
error = kStatus_USB_InvalidRequest;
}
break;
}
case kUSB_DeviceHidEventRequestReportBuffer: {
usb_device_hid_report_struct_t *report = (usb_device_hid_report_struct_t*)param;
if (report->reportType == USB_DEVICE_HID_REQUEST_GET_REPORT_TYPE_FEATURE && report->reportId == 0 && report->reportLength <= sizeof(usbMouseFeatBuffer)) {
// The Linux implementation of SetReport when initializing a
// device with a single resolution multiplier value is broken,
// sending an empty report, and as a result the
// kUSB_DeviceHidEventSetReport case above isn't triggered at
// all; but it only sends this report when it detects the
// resolution multiplier, and the intention is to activate the
// feature, so turn high-res mode on here.
Macros_ReportPrintf(NULL, "USB Mouse: Request Report Buffer -> 1");
report->reportBuffer = usbMouseFeatBuffer;
usbMouseFeatBuffer[0] = 0x1;
error = kStatus_USB_Success;
} else {
error = kStatus_USB_AllocFail;
}
break;
}
case kUSB_DeviceHidEventSetProtocol: {
uint8_t report = *(uint16_t*)param;
if (report <= 1) {
hidHandle->protocol = report;
error = kStatus_USB_Success;
}
else {
error = kStatus_USB_InvalidRequest;
}
break;
}
default:
break;
}
return error;
}
#endif
void UsbMouseSendActiveReport(void)
{
#ifdef __ZEPHYR__
UsbCompatibility_SendMouseReport(ActiveUsbMouseReport);
SwitchActiveUsbMouseReport();
#else
UsbReportUpdateSemaphore |= 1 << USB_MOUSE_INTERFACE_INDEX;
usb_status_t status = UsbMouseAction();
if (status != kStatus_USB_Success) {
UsbReportUpdateSemaphore &= ~(1 << USB_MOUSE_INTERFACE_INDEX);
EventVector_Set(EventVector_ResendUsbReports);
}
#endif
}
usb_status_t UsbMouseCheckIdleElapsed()
{
return kStatus_USB_Busy;
}
usb_status_t UsbMouseCheckReportReady(bool* buttonsChanged)
{
// Send out the mouse position and wheel values continuously if the report is not zeros, but only send the mouse button states when they change.
if ((memcmp(ActiveUsbMouseReport, GetInactiveUsbMouseReport(), sizeof(usb_mouse_report_t)) != 0) ||
ActiveUsbMouseReport->x || ActiveUsbMouseReport->y ||
ActiveUsbMouseReport->wheelX || ActiveUsbMouseReport->wheelY) {
if (buttonsChanged != NULL) {
*buttonsChanged = ActiveUsbMouseReport->buttons != GetInactiveUsbMouseReport()->buttons;
}
return kStatus_USB_Success;
}
return UsbMouseCheckIdleElapsed();
}
void UsbMouse_MergeReports(usb_mouse_report_t* sourceReport, usb_mouse_report_t* targetReport)
{
targetReport->buttons |= sourceReport->buttons;
targetReport->x += sourceReport->x;
targetReport->y += sourceReport->y;
targetReport->wheelX += sourceReport->wheelX;
targetReport->wheelY += sourceReport->wheelY;
sourceReport->x = 0;
sourceReport->y = 0;
sourceReport->wheelX = 0;
sourceReport->wheelY = 0;
}