ReactOS  0.4.15-dev-3428-g0609db5
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 
75 #define MS_INPORT_SIGNATURE 0x02
76 
77 #define MS_BUTTON_MIDDLE 0x01
78 #define MS_BUTTON_LEFT 0x02
79 #define MS_BUTTON_RIGHT 0x04
80 
81 /*
82  * Logitech
83  */
84 #define LOG_BM_DATA 0x00
85 
86 #define LOG_BM_SIGNATURE 0x01
87  #define LOG_SIGNATURE_BYTE 0xA5
88 
89 #define LOG_BM_CONTROL 0x02
90  #define LOG_ENABLE_IRQ 0x00
91  #define LOG_DISABLE_IRQ 0x10
92 
93  #define LOG_READ_X_LOW 0x80
94  #define LOG_READ_X_HIGH 0xA0
95  #define LOG_READ_Y_LOW 0xC0
96  #define LOG_READ_Y_HIGH 0xE0
97 
98 #define LOG_BM_CONFIG 0x03
99  #define LOG_DEFAULT_MODE 0x90
100  #define LOG_CONFIG_BYTE 0x91
101 
102 #define LOG_BUTTON_RIGHT 0x20
103 #define LOG_BUTTON_MIDDLE 0x40
104 #define LOG_BUTTON_LEFT 0x80
105 
106 /* FUNCTIONS ******************************************************************/
107 
108 VOID
109 NTAPI
111  _In_ PKDPC Dpc,
113  _Inout_ PIRP Irp,
115 {
116  PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
117  KIRQL OldIrql;
118  ULONG DummyInputDataConsumed;
119  INPORT_RAW_DATA RawData;
120 
124 
125  /* Copy raw data */
127  RawData = DeviceExtension->RawData;
129 
130  /* Fill out fields */
131  DeviceExtension->MouseInputData.LastX = RawData.DeltaX;
132  DeviceExtension->MouseInputData.LastY = RawData.DeltaY;
133  DeviceExtension->MouseInputData.ButtonFlags = 0;
134  if (RawData.ButtonDiff != 0)
135  {
136  switch (DeviceExtension->MouseType)
137  {
138  case NecBusMouse:
139  {
140  if (RawData.ButtonDiff & NEC_BUTTON_LEFT)
141  {
142  if (RawData.Buttons & NEC_BUTTON_LEFT)
143  DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
144  else
146  }
147  if (RawData.ButtonDiff & NEC_BUTTON_RIGHT)
148  {
149  if (RawData.Buttons & NEC_BUTTON_RIGHT)
151  else
153  }
154 
155  break;
156  }
157 
158  case MsInPortMouse:
159  {
160  /* Button flags have to be inverted */
161  if (RawData.ButtonDiff & MS_BUTTON_LEFT)
162  {
163  if (RawData.Buttons & MS_BUTTON_LEFT)
165  else
166  DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
167  }
168  if (RawData.ButtonDiff & MS_BUTTON_RIGHT)
169  {
170  if (RawData.Buttons & MS_BUTTON_RIGHT)
172  else
174  }
175  if (RawData.ButtonDiff & MS_BUTTON_MIDDLE)
176  {
177  if (RawData.Buttons & MS_BUTTON_MIDDLE)
179  else
181  }
182 
183  break;
184  }
185 
186  case LogitechBusMouse:
187  {
188  if (RawData.ButtonDiff & LOG_BUTTON_LEFT)
189  {
190  if (RawData.Buttons & LOG_BUTTON_LEFT)
191  DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
192  else
194  }
195  if (RawData.ButtonDiff & LOG_BUTTON_RIGHT)
196  {
197  if (RawData.Buttons & LOG_BUTTON_RIGHT)
199  else
201  }
202  if (RawData.ButtonDiff & LOG_BUTTON_MIDDLE)
203  {
204  if (RawData.Buttons & LOG_BUTTON_MIDDLE)
206  else
208  }
209 
210  break;
211  }
212  }
213  }
214 
215  /* Send mouse packet */
216  (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(
217  DeviceExtension->ClassDeviceObject,
218  &DeviceExtension->MouseInputData,
219  &DeviceExtension->MouseInputData + 1,
220  &DummyInputDataConsumed);
221 }
222 
223 BOOLEAN
224 NTAPI
228 {
229  UCHAR Buttons;
230  ULONG ButtonDiff;
231  CHAR DeltaX, DeltaY;
232  PINPORT_DEVICE_EXTENSION DeviceExtension = Context;
233 
235 
236  switch (DeviceExtension->MouseType)
237  {
238  case NecBusMouse:
239  {
240  WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
242 
243  WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
245  DeltaX = READ_MOUSE(DeviceExtension, NEC_BM_DATA) & 0x0F;
246 
247  WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
249  DeltaX |= READ_MOUSE(DeviceExtension, NEC_BM_DATA) << 4;
250 
251  WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
253  DeltaY = READ_MOUSE(DeviceExtension, NEC_BM_DATA) & 0x0F;
254 
255  WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
257  Buttons = READ_MOUSE(DeviceExtension, NEC_BM_DATA);
258  DeltaY |= Buttons << 4;
260 
261  WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL,
263 
264  break;
265  }
266 
267  case MsInPortMouse:
268  {
269  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE);
270  WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA,
272 
273  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_X);
274  DeltaX = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
275 
276  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_Y);
277  DeltaY = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
278 
279  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_BTNS);
280  Buttons = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
282 
283  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE);
284  WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA,
286 
287  break;
288  }
289 
290  case LogitechBusMouse:
291  {
292  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_X_LOW);
293  DeltaX = READ_MOUSE(DeviceExtension, LOG_BM_DATA) & 0x0F;
294 
295  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_X_HIGH);
296  DeltaX |= READ_MOUSE(DeviceExtension, LOG_BM_DATA) << 4;
297 
298  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_Y_LOW);
299  DeltaY = READ_MOUSE(DeviceExtension, LOG_BM_DATA) & 0x0F;
300 
301  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_Y_HIGH);
302  Buttons = READ_MOUSE(DeviceExtension, LOG_BM_DATA);
303  DeltaY |= Buttons << 4;
305 
306  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_ENABLE_IRQ);
307 
308  break;
309  }
310  }
311 
312  ButtonDiff = DeviceExtension->MouseButtonState ^ Buttons;
313  DeviceExtension->MouseButtonState = Buttons;
314 
315  /*
316  * Bus mouse devices don't have a status register to check
317  * whether this interrupt is indeed for us.
318  */
319  if ((DeltaX == 0) && (DeltaY == 0) && (ButtonDiff == 0))
320  {
321  /* We just pretend that the interrupt is not ours */
322  return FALSE;
323  }
324  else
325  {
326  DeviceExtension->RawData.DeltaX = DeltaX;
327  DeviceExtension->RawData.DeltaY = DeltaY;
328  DeviceExtension->RawData.Buttons = Buttons;
329  DeviceExtension->RawData.ButtonDiff = ButtonDiff;
330 
331  IoRequestDpc(DeviceExtension->Self, NULL, NULL);
332 
333  return TRUE;
334  }
335 }
336 
337 CODE_SEG("PAGE")
338 VOID
339 NTAPI
341  _In_ PINPORT_DEVICE_EXTENSION DeviceExtension)
342 {
343  PAGED_CODE();
344 
345  /* Initialize mouse and disable interrupts */
346  switch (DeviceExtension->MouseType)
347  {
348  case NecBusMouse:
350 
351  /* Setup interrupt rate (unavailable on hireso machines) */
352  if (DeviceExtension->IoBase != NEC_BM_HIRESO_BASE)
353  WRITE_MOUSE(DeviceExtension, NEC_BM_INT_RATE, NEC_RATE_60_HZ);
354 
355  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_INT_DISABLE);
356  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_NO_CLEAR);
357  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR);
358  break;
359 
360  case MsInPortMouse:
361  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_RESET);
362  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE);
363  WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA, INPORT_MODE_BASE);
364  break;
365 
366  case LogitechBusMouse:
367  WRITE_MOUSE(DeviceExtension, LOG_BM_CONFIG, LOG_DEFAULT_MODE);
368  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_DISABLE_IRQ);
369  break;
370  }
371 }
372 
373 BOOLEAN
374 NTAPI
377 {
379 
380  /* Enable interrupts */
381  switch (DeviceExtension->MouseType)
382  {
383  case NecBusMouse:
384  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_INT_ENABLE);
385  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_NO_CLEAR);
386  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR);
387  break;
388 
389  case MsInPortMouse:
390  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE);
391  WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA,
393  break;
394 
395  case LogitechBusMouse:
396  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_ENABLE_IRQ);
397  break;
398  }
399 
400  return TRUE;
401 }
402 
403 BOOLEAN
404 NTAPI
407 {
409 
410  /* Disable interrupts */
411  switch (DeviceExtension->MouseType)
412  {
413  case NecBusMouse:
414  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_INT_DISABLE);
415  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_NO_CLEAR);
416  WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR);
417  break;
418 
419  case MsInPortMouse:
420  WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE);
421  WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA, INPORT_MODE_BASE);
422  break;
423 
424  case LogitechBusMouse:
425  WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_DISABLE_IRQ);
426  break;
427  }
428 
429  return TRUE;
430 }
#define INPORT_MODE_HOLD
Definition: hardware.c:73
#define INPORT_REG_Y
Definition: hardware.c:66
MOUSE_INPUT_DATA MouseInputData
Definition: inport.h:70
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:107
#define MOUSE_MIDDLE_BUTTON_DOWN
Definition: ntddmou.h:50
#define MOUSE_LEFT_BUTTON_DOWN
Definition: ntddmou.h:46
#define NEC_RATE_60_HZ
Definition: hardware.c:51
#define _In_opt_
Definition: ms_sal.h:309
PDEVICE_OBJECT ClassDeviceObject
Definition: inport.h:66
#define _Inout_
Definition: ms_sal.h:378
#define LOG_READ_X_HIGH
Definition: hardware.c:94
#define NEC_INPUT_CAPTURE
Definition: hardware.c:39
#define LOG_BM_CONTROL
Definition: hardware.c:89
#define NEC_PPI_INT_ENABLE
Definition: hardware.c:43
BOOLEAN NTAPI InPortStartMouse(_In_ PVOID SynchronizeContext)
Definition: hardware.c:375
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define INPORT_MODE_BASE
Definition: hardware.c:72
#define NEC_PPI_HC_CLEAR
Definition: hardware.c:46
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:372
char CHAR
Definition: xmlstorage.h:175
#define INPORT_REG_X
Definition: hardware.c:65
#define MS_BUTTON_LEFT
Definition: hardware.c:78
#define NEC_READ_X_LOW
Definition: hardware.c:34
#define MS_BUTTON_RIGHT
Definition: hardware.c:79
UCHAR Buttons
Definition: inport.h:38
PDEVICE_OBJECT Self
Definition: inport.h:44
INPORT_MOUSE_TYPE MouseType
Definition: inport.h:51
#define INPORT_REG_MODE
Definition: hardware.c:67
#define MS_BUTTON_MIDDLE
Definition: hardware.c:77
#define NEC_BM_INT_RATE
Definition: hardware.c:49
#define NEC_BUTTON_LEFT
Definition: hardware.c:58
#define NEC_INT_ENABLE
Definition: hardware.c:31
#define INPORT_MODE_IRQ
Definition: hardware.c:71
#define NEC_BM_HIRESO_BASE
Definition: hardware.c:55
UCHAR KIRQL
Definition: env_spec_w32.h:591
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define NEC_PPI_INT_DISABLE
Definition: hardware.c:44
ULONG ButtonDiff
Definition: inport.h:39
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
INPORT_RAW_DATA RawData
Definition: inport.h:62
#define FALSE
Definition: types.h:117
_In_ PIRP Irp
Definition: csq.h:116
#define LOG_BUTTON_LEFT
Definition: hardware.c:104
VOID NTAPI KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt, IN KIRQL OldIrql)
Definition: spinlock.c:171
unsigned char BOOLEAN
#define NEC_READ_Y_LOW
Definition: hardware.c:36
#define _In_
Definition: ms_sal.h:308
VOID NTAPI InPortInitializeMouse(_In_ PINPORT_DEVICE_EXTENSION DeviceExtension)
Definition: hardware.c:340
#define READ_MOUSE(DeviceExtension, Port)
Definition: hardware.c:19
#define MS_INPORT_DATA
Definition: hardware.c:70
PKINTERRUPT InterruptObject
Definition: inport.h:54
#define LOG_BM_CONFIG
Definition: hardware.c:98
static const TBBUTTON Buttons[]
Definition: mplay32.c:41
#define NEC_PPI_DEFAULT_MODE
Definition: hardware.c:47
#define LOG_DEFAULT_MODE
Definition: hardware.c:99
FORCEINLINE VOID IoRequestDpc(_Inout_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Irp, _In_opt_ __drv_aliasesMem PVOID Context)
Definition: iofuncs.h:2750
#define LOG_READ_Y_HIGH
Definition: hardware.c:96
#define NEC_INT_DISABLE
Definition: hardware.c:32
#define MOUSE_LEFT_BUTTON_UP
Definition: ntddmou.h:47
#define MOUSE_MIDDLE_BUTTON_UP
Definition: ntddmou.h:51
#define INPORT_RESET
Definition: hardware.c:68
#define MOUSE_RIGHT_BUTTON_DOWN
Definition: ntddmou.h:48
KIRQL NTAPI KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
Definition: spinlock.c:154
unsigned char UCHAR
Definition: xmlstorage.h:181
VOID(STDAPICALLTYPE * PSERVICE_CALLBACK_ROUTINE)(IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2, IN OUT PVOID SystemArgument3)
Definition: kbdmou.h:86
#define NEC_INPUT_HOLD
Definition: hardware.c:40
USHORT ButtonFlags
Definition: ntddmou.h:82
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:790
Definition: ketypes.h:687
#define LOG_READ_Y_LOW
Definition: hardware.c:95
#define MS_INPORT_CONTROL
Definition: hardware.c:63
#define NEC_BM_CONTROL
Definition: hardware.c:30
#define NEC_BM_DATA
Definition: hardware.c:28
#define LOG_BUTTON_MIDDLE
Definition: hardware.c:103
_In_ PKSYNCHRONIZE_ROUTINE _In_opt_ __drv_aliasesMem PVOID SynchronizeContext
Definition: kefuncs.h:536
#define WRITE_MOUSE(DeviceExtension, Port, Data)
Definition: hardware.c:22
#define INPORT_REG_BTNS
Definition: hardware.c:64
#define NEC_BM_CONFIG
Definition: hardware.c:42
#define NEC_BUTTON_RIGHT
Definition: hardware.c:57
#define NEC_READ_X_HIGH
Definition: hardware.c:35
BOOLEAN NTAPI InPortIsr(_In_ PKINTERRUPT Interrupt, _In_ PVOID Context)
Definition: hardware.c:225
#define NULL
Definition: types.h:112
#define LOG_BUTTON_RIGHT
Definition: hardware.c:102
struct tagContext Context
Definition: acpixf.h:1034
unsigned int ULONG
Definition: retypes.h:1
#define MOUSE_RIGHT_BUTTON_UP
Definition: ntddmou.h:49
#define LOG_BM_DATA
Definition: hardware.c:84
#define LOG_DISABLE_IRQ
Definition: hardware.c:91
BOOLEAN NTAPI InPortStopMouse(_In_ PVOID SynchronizeContext)
Definition: hardware.c:405
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
#define LOG_READ_X_LOW
Definition: hardware.c:93
#define NEC_READ_Y_HIGH
Definition: hardware.c:37
VOID NTAPI InPortDpcForIsr(_In_ PKDPC Dpc, _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _In_opt_ PVOID Context)
Definition: hardware.c:110
#define NEC_PPI_HC_NO_CLEAR
Definition: hardware.c:45
#define PAGED_CODE()
#define LOG_ENABLE_IRQ
Definition: hardware.c:90