ReactOS 0.4.16-dev-136-g52192f1
hardware.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS InPort (Bus) Mouse Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Hardware support code
5 * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
6 */
7
8/* Note: Some code was taken from Linux */
9
10/* INCLUDES *******************************************************************/
11
12#include "inport.h"
13
14#define NDEBUG
15#include <debug.h>
16
17/* GLOBALS ********************************************************************/
18
19#define READ_MOUSE(DeviceExtension, Port) \
20 READ_PORT_UCHAR((DeviceExtension)->IoBase + (Port))
21
22#define WRITE_MOUSE(DeviceExtension, Port, Data) \
23 WRITE_PORT_UCHAR((DeviceExtension)->IoBase + (Port), (Data))
24
25/*
26 * NEC
27 */
28#define NEC_BM_DATA 0x00
29
30#define NEC_BM_CONTROL 0x04
31 #define NEC_INT_ENABLE 0x00
32 #define NEC_INT_DISABLE 0x10
33
34 #define NEC_READ_X_LOW 0x00
35 #define NEC_READ_X_HIGH 0x20
36 #define NEC_READ_Y_LOW 0x40
37 #define NEC_READ_Y_HIGH 0x60
38
39 #define NEC_INPUT_CAPTURE 0x00
40 #define NEC_INPUT_HOLD 0x80
41
42#define NEC_BM_CONFIG 0x06
43 #define NEC_PPI_INT_ENABLE 0x08
44 #define NEC_PPI_INT_DISABLE 0x09
45 #define NEC_PPI_HC_NO_CLEAR 0x0E
46 #define NEC_PPI_HC_CLEAR 0x0F
47 #define NEC_PPI_DEFAULT_MODE 0x93
48
49#define NEC_BM_INT_RATE 0x4002
50 #define NEC_RATE_120_HZ 0x00
51 #define NEC_RATE_60_HZ 0x01
52 #define NEC_RATE_30_HZ 0x02
53 #define NEC_RATE_15_HZ 0x03
54
55#define NEC_BM_HIRESO_BASE (PUCHAR)0x61
56
57#define NEC_BUTTON_RIGHT 0x20
58#define NEC_BUTTON_LEFT 0x80
59
60/*
61 * Microsoft InPort
62 */
63#define MS_INPORT_CONTROL 0x00
64 #define INPORT_REG_BTNS 0x00
65 #define INPORT_REG_X 0x01
66 #define INPORT_REG_Y 0x02
67 #define INPORT_REG_MODE 0x07
68 #define INPORT_RESET 0x80
69
70#define MS_INPORT_DATA 0x01
71 #define INPORT_MODE_IRQ 0x01
72 #define INPORT_MODE_BASE 0x10
73 #define INPORT_MODE_HOLD 0x20
74 #define INPORT_HAS_MOVED 0x40
75
76#define MS_INPORT_SIGNATURE 0x02
77
78#define MS_BUTTON_RIGHT 0x01
79#define MS_BUTTON_MIDDLE 0x02
80#define MS_BUTTON_LEFT 0x04
81
82/*
83 * Logitech
84 */
85#define LOG_BM_DATA 0x00
86
87#define LOG_BM_SIGNATURE 0x01
88 #define LOG_SIGNATURE_BYTE 0xA5
89
90#define LOG_BM_CONTROL 0x02
91 #define LOG_ENABLE_IRQ 0x00
92 #define LOG_DISABLE_IRQ 0x10
93
94 #define LOG_READ_X_LOW 0x80
95 #define LOG_READ_X_HIGH 0xA0
96 #define LOG_READ_Y_LOW 0xC0
97 #define LOG_READ_Y_HIGH 0xE0
98
99#define LOG_BM_CONFIG 0x03
100 #define LOG_DEFAULT_MODE 0x90
101 #define LOG_CONFIG_BYTE 0x91
102
103#define LOG_BUTTON_RIGHT 0x20
104#define LOG_BUTTON_MIDDLE 0x40
105#define LOG_BUTTON_LEFT 0x80
106
107/* FUNCTIONS ******************************************************************/
108
109VOID
110NTAPI
112 _In_ PKDPC Dpc,
116{
117 PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
119 ULONG DummyInputDataConsumed;
120 INPORT_RAW_DATA RawData;
121
125
126 /* Copy raw data */
128 RawData = DeviceExtension->RawData;
130
131 /* Fill out fields */
132 DeviceExtension->MouseInputData.LastX = RawData.DeltaX;
133 DeviceExtension->MouseInputData.LastY = RawData.DeltaY;
134 DeviceExtension->MouseInputData.ButtonFlags = 0;
135 if (RawData.ButtonDiff != 0)
136 {
137 switch (DeviceExtension->MouseType)
138 {
139 case NecBusMouse:
140 {
141 if (RawData.ButtonDiff & NEC_BUTTON_LEFT)
142 {
143 if (RawData.Buttons & NEC_BUTTON_LEFT)
145 else
147 }
148 if (RawData.ButtonDiff & NEC_BUTTON_RIGHT)
149 {
150 if (RawData.Buttons & NEC_BUTTON_RIGHT)
152 else
154 }
155
156 break;
157 }
158
159 case MsInPortMouse:
160 {
161 /* Button flags have to be inverted */
162 if (RawData.ButtonDiff & MS_BUTTON_LEFT)
163 {
164 if (RawData.Buttons & MS_BUTTON_LEFT)
166 else
168 }
169 if (RawData.ButtonDiff & MS_BUTTON_RIGHT)
170 {
171 if (RawData.Buttons & MS_BUTTON_RIGHT)
173 else
175 }
176 if (RawData.ButtonDiff & MS_BUTTON_MIDDLE)
177 {
178 if (RawData.Buttons & MS_BUTTON_MIDDLE)
180 else
182 }
183
184 break;
185 }
186
187 case LogitechBusMouse:
188 {
189 if (RawData.ButtonDiff & LOG_BUTTON_LEFT)
190 {
191 if (RawData.Buttons & LOG_BUTTON_LEFT)
193 else
195 }
196 if (RawData.ButtonDiff & LOG_BUTTON_RIGHT)
197 {
198 if (RawData.Buttons & LOG_BUTTON_RIGHT)
200 else
202 }
203 if (RawData.ButtonDiff & LOG_BUTTON_MIDDLE)
204 {
205 if (RawData.Buttons & LOG_BUTTON_MIDDLE)
207 else
209 }
210
211 break;
212 }
213 }
214 }
215
216 /* Send mouse packet */
217 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(
218 DeviceExtension->ClassDeviceObject,
219 &DeviceExtension->MouseInputData,
220 &DeviceExtension->MouseInputData + 1,
221 &DummyInputDataConsumed);
222}
223
225NTAPI
229{
231 ULONG ButtonDiff;
232 CHAR DeltaX, DeltaY;
233 PINPORT_DEVICE_EXTENSION DeviceExtension = Context;
234
236
237 switch (DeviceExtension->MouseType)
238 {
239 case NecBusMouse:
240 {
241 WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
243
244 WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
246 DeltaX = READ_MOUSE(DeviceExtension, NEC_BM_DATA) & 0x0F;
247
248 WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
250 DeltaX |= READ_MOUSE(DeviceExtension, NEC_BM_DATA) << 4;
251
252 WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
254 DeltaY = READ_MOUSE(DeviceExtension, NEC_BM_DATA) & 0x0F;
255
256 WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
258 Buttons = READ_MOUSE(DeviceExtension, NEC_BM_DATA);
259 DeltaY |= Buttons << 4;
261
262 WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
264
265 break;
266 }
267
268 case MsInPortMouse:
269 {
271 WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA,
273
275 Buttons = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
276
278 {
279 WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_X);
280 DeltaX = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
281
282 WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_Y);
283 DeltaY = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
284 }
285 else
286 {
287 DeltaX = 0;
288 DeltaY = 0;
289 }
290
292
294 WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA,
296
297 break;
298 }
299
300 case LogitechBusMouse:
301 {
302 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_X_LOW);
303 DeltaX = READ_MOUSE(DeviceExtension, LOG_BM_DATA) & 0x0F;
304
305 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_X_HIGH);
306 DeltaX |= READ_MOUSE(DeviceExtension, LOG_BM_DATA) << 4;
307
308 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_Y_LOW);
309 DeltaY = READ_MOUSE(DeviceExtension, LOG_BM_DATA) & 0x0F;
310
311 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_Y_HIGH);
312 Buttons = READ_MOUSE(DeviceExtension, LOG_BM_DATA);
313 DeltaY |= Buttons << 4;
315
316 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_ENABLE_IRQ);
317
318 break;
319 }
320 }
321
322 ButtonDiff = DeviceExtension->MouseButtonState ^ Buttons;
323 DeviceExtension->MouseButtonState = Buttons;
324
325 /*
326 * Bus mouse devices don't have a status register to check
327 * whether this interrupt is indeed for us.
328 */
329 if ((DeltaX == 0) && (DeltaY == 0) && (ButtonDiff == 0))
330 {
331 /* We just pretend that the interrupt is not ours */
332 return FALSE;
333 }
334 else
335 {
336 DeviceExtension->RawData.DeltaX = DeltaX;
337 DeviceExtension->RawData.DeltaY = DeltaY;
338 DeviceExtension->RawData.Buttons = Buttons;
339 DeviceExtension->RawData.ButtonDiff = ButtonDiff;
340
341 IoRequestDpc(DeviceExtension->Self, NULL, NULL);
342
343 return TRUE;
344 }
345}
346
347CODE_SEG("PAGE")
348VOID
349NTAPI
351 _In_ PINPORT_DEVICE_EXTENSION DeviceExtension)
352{
353 PAGED_CODE();
354
355 /* Initialize mouse and disable interrupts */
356 switch (DeviceExtension->MouseType)
357 {
358 case NecBusMouse:
360
361 /* Setup interrupt rate (unavailable on hireso machines) */
362 if (DeviceExtension->IoBase != NEC_BM_HIRESO_BASE)
363 WRITE_MOUSE(DeviceExtension, NEC_BM_INT_RATE, NEC_RATE_60_HZ);
364
367 WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR);
368 break;
369
370 case MsInPortMouse:
371 WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_RESET);
374 break;
375
376 case LogitechBusMouse:
377 WRITE_MOUSE(DeviceExtension, LOG_BM_CONFIG, LOG_DEFAULT_MODE);
378 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_DISABLE_IRQ);
379 break;
380 }
381}
382
384NTAPI
387{
389
390 /* Enable interrupts */
391 switch (DeviceExtension->MouseType)
392 {
393 case NecBusMouse:
396 WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR);
397 break;
398
399 case MsInPortMouse:
401 WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA,
403 break;
404
405 case LogitechBusMouse:
406 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_ENABLE_IRQ);
407 break;
408 }
409
410 return TRUE;
411}
412
414NTAPI
417{
419
420 /* Disable interrupts */
421 switch (DeviceExtension->MouseType)
422 {
423 case NecBusMouse:
426 WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR);
427 break;
428
429 case MsInPortMouse:
432 break;
433
434 case LogitechBusMouse:
435 WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_DISABLE_IRQ);
436 break;
437 }
438
439 return TRUE;
440}
#define PAGED_CODE()
#define CODE_SEG(...)
unsigned char BOOLEAN
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define LOG_READ_Y_HIGH
Definition: hardware.c:97
#define LOG_BUTTON_LEFT
Definition: hardware.c:105
#define MS_INPORT_CONTROL
Definition: hardware.c:63
#define NEC_INT_ENABLE
Definition: hardware.c:31
#define NEC_BUTTON_RIGHT
Definition: hardware.c:57
#define WRITE_MOUSE(DeviceExtension, Port, Data)
Definition: hardware.c:22
#define LOG_READ_X_HIGH
Definition: hardware.c:95
#define LOG_ENABLE_IRQ
Definition: hardware.c:91
#define LOG_BM_CONFIG
Definition: hardware.c:99
#define INPORT_MODE_BASE
Definition: hardware.c:72
#define NEC_PPI_INT_ENABLE
Definition: hardware.c:43
#define LOG_DEFAULT_MODE
Definition: hardware.c:100
#define NEC_READ_Y_LOW
Definition: hardware.c:36
#define NEC_RATE_60_HZ
Definition: hardware.c:51
#define INPORT_REG_Y
Definition: hardware.c:66
#define NEC_BUTTON_LEFT
Definition: hardware.c:58
#define LOG_BUTTON_RIGHT
Definition: hardware.c:103
#define INPORT_REG_X
Definition: hardware.c:65
#define NEC_PPI_INT_DISABLE
Definition: hardware.c:44
#define LOG_BUTTON_MIDDLE
Definition: hardware.c:104
#define LOG_BM_CONTROL
Definition: hardware.c:90
VOID NTAPI InPortInitializeMouse(_In_ PINPORT_DEVICE_EXTENSION DeviceExtension)
Definition: hardware.c:350
#define INPORT_MODE_IRQ
Definition: hardware.c:71
#define READ_MOUSE(DeviceExtension, Port)
Definition: hardware.c:19
#define NEC_BM_CONTROL
Definition: hardware.c:30
#define NEC_READ_X_HIGH
Definition: hardware.c:35
#define LOG_BM_DATA
Definition: hardware.c:85
#define NEC_BM_HIRESO_BASE
Definition: hardware.c:55
#define NEC_PPI_HC_NO_CLEAR
Definition: hardware.c:45
#define NEC_INPUT_CAPTURE
Definition: hardware.c:39
#define MS_BUTTON_MIDDLE
Definition: hardware.c:79
#define NEC_READ_Y_HIGH
Definition: hardware.c:37
#define INPORT_HAS_MOVED
Definition: hardware.c:74
#define MS_INPORT_DATA
Definition: hardware.c:70
#define LOG_READ_Y_LOW
Definition: hardware.c:96
#define NEC_READ_X_LOW
Definition: hardware.c:34
#define MS_BUTTON_RIGHT
Definition: hardware.c:78
#define NEC_BM_CONFIG
Definition: hardware.c:42
#define INPORT_REG_MODE
Definition: hardware.c:67
#define LOG_READ_X_LOW
Definition: hardware.c:94
#define NEC_BM_DATA
Definition: hardware.c:28
#define INPORT_REG_BTNS
Definition: hardware.c:64
#define NEC_INPUT_HOLD
Definition: hardware.c:40
#define NEC_PPI_DEFAULT_MODE
Definition: hardware.c:47
#define NEC_INT_DISABLE
Definition: hardware.c:32
#define MS_BUTTON_LEFT
Definition: hardware.c:80
#define NEC_BM_INT_RATE
Definition: hardware.c:49
#define INPORT_RESET
Definition: hardware.c:68
#define NEC_PPI_HC_CLEAR
Definition: hardware.c:46
#define LOG_DISABLE_IRQ
Definition: hardware.c:92
#define INPORT_MODE_HOLD
Definition: hardware.c:73
UCHAR KIRQL
Definition: env_spec_w32.h:591
KSERVICE_ROUTINE InPortIsr
Definition: inport.h:107
KSYNCHRONIZE_ROUTINE InPortStopMouse
Definition: inport.h:113
KSYNCHRONIZE_ROUTINE InPortStartMouse
Definition: inport.h:111
IO_DPC_ROUTINE InPortDpcForIsr
Definition: inport.h:109
@ NecBusMouse
Definition: inport.h:29
@ MsInPortMouse
Definition: inport.h:30
@ LogitechBusMouse
Definition: inport.h:31
VOID(STDAPICALLTYPE * PSERVICE_CALLBACK_ROUTINE)(IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2, IN OUT PVOID SystemArgument3)
Definition: kbdmou.h:86
static const TBBUTTON Buttons[]
Definition: mplay32.c:41
#define _Inout_
Definition: ms_sal.h:378
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define MOUSE_LEFT_BUTTON_DOWN
Definition: ntddmou.h:46
#define MOUSE_LEFT_BUTTON_UP
Definition: ntddmou.h:47
#define MOUSE_MIDDLE_BUTTON_DOWN
Definition: ntddmou.h:50
#define MOUSE_RIGHT_BUTTON_UP
Definition: ntddmou.h:49
#define MOUSE_MIDDLE_BUTTON_UP
Definition: ntddmou.h:51
#define MOUSE_RIGHT_BUTTON_DOWN
Definition: ntddmou.h:48
KIRQL NTAPI KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
Definition: spinlock.c:154
VOID NTAPI KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt, IN KIRQL OldIrql)
Definition: spinlock.c:171
INPORT_MOUSE_TYPE MouseType
Definition: inport.h:51
PDEVICE_OBJECT Self
Definition: inport.h:44
MOUSE_INPUT_DATA MouseInputData
Definition: inport.h:70
INPORT_RAW_DATA RawData
Definition: inport.h:62
PDEVICE_OBJECT ClassDeviceObject
Definition: inport.h:66
PKINTERRUPT InterruptObject
Definition: inport.h:54
UCHAR Buttons
Definition: inport.h:38
ULONG ButtonDiff
Definition: inport.h:39
Definition: ketypes.h:699
USHORT ButtonFlags
Definition: ntddmou.h:82
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG
Definition: typedefs.h:59
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:379
FORCEINLINE VOID IoRequestDpc(_Inout_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Irp, _In_opt_ __drv_aliasesMem PVOID Context)
Definition: iofuncs.h:2750
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
_In_ PKSYNCHRONIZE_ROUTINE _In_opt_ __drv_aliasesMem PVOID SynchronizeContext
Definition: kefuncs.h:525
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175