Sync to trunk r65566.
[reactos.git] / drivers / input / i8042prt / readwrite.c
1 /*
2 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/input/i8042prt/readwrite.c
5 * PURPOSE: Read/write port functions
6 * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
7 Copyright Jason Filby (jasonfilby@yahoo.com)
8 Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
9 Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include "i8042prt.h"
15
16 #include <debug.h>
17
18 /* FUNCTIONS *****************************************************************/
19
20 VOID
21 i8042Flush(
22 IN PPORT_DEVICE_EXTENSION DeviceExtension)
23 {
24 UCHAR Ignore;
25
26 /* Flush output buffer */
27 while (NT_SUCCESS(i8042ReadData(DeviceExtension, KBD_OBF /* | MOU_OBF*/, &Ignore))) {
28 KeStallExecutionProcessor(50);
29 TRACE_(I8042PRT, "Output data flushed\n");
30 }
31
32 /* Flush input buffer */
33 while (NT_SUCCESS(i8042ReadData(DeviceExtension, KBD_IBF, &Ignore))) {
34 KeStallExecutionProcessor(50);
35 TRACE_(I8042PRT, "Input data flushed\n");
36 }
37 }
38
39 BOOLEAN
40 i8042IsrWritePort(
41 IN PPORT_DEVICE_EXTENSION DeviceExtension,
42 IN UCHAR Value,
43 IN UCHAR SelectCmd OPTIONAL)
44 {
45 if (SelectCmd)
46 if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, SelectCmd))
47 return FALSE;
48
49 return i8042Write(DeviceExtension, DeviceExtension->DataPort, Value);
50 }
51
52 /*
53 * FUNCTION: Read data from port 0x60
54 */
55 NTSTATUS
56 i8042ReadData(
57 IN PPORT_DEVICE_EXTENSION DeviceExtension,
58 IN UCHAR StatusFlags,
59 OUT PUCHAR Data)
60 {
61 UCHAR PortStatus;
62 NTSTATUS Status;
63
64 Status = i8042ReadStatus(DeviceExtension, &PortStatus);
65 if (!NT_SUCCESS(Status))
66 return Status;
67
68 // If data is available
69 if (PortStatus & StatusFlags)
70 {
71 *Data = READ_PORT_UCHAR(DeviceExtension->DataPort);
72 INFO_(I8042PRT, "Read: 0x%02x (status: 0x%x)\n", Data[0], PortStatus);
73
74 // If the data is valid (not timeout, not parity error)
75 if ((PortStatus & KBD_PERR) == 0)
76 return STATUS_SUCCESS;
77 }
78 return STATUS_UNSUCCESSFUL;
79 }
80
81 NTSTATUS
82 i8042ReadStatus(
83 IN PPORT_DEVICE_EXTENSION DeviceExtension,
84 OUT PUCHAR Status)
85 {
86 ASSERT(DeviceExtension->ControlPort != NULL);
87 *Status = READ_PORT_UCHAR(DeviceExtension->ControlPort);
88 return STATUS_SUCCESS;
89 }
90
91 /*
92 * FUNCTION: Read data from data port
93 */
94 NTSTATUS
95 i8042ReadDataWait(
96 IN PPORT_DEVICE_EXTENSION DeviceExtension,
97 OUT PUCHAR Data)
98 {
99 ULONG Counter;
100 NTSTATUS Status;
101
102 Counter = DeviceExtension->Settings.PollingIterations;
103
104 while (Counter--)
105 {
106 Status = i8042ReadKeyboardData(DeviceExtension, Data);
107
108 if (NT_SUCCESS(Status))
109 return Status;
110
111 KeStallExecutionProcessor(50);
112 }
113
114 /* Timed out */
115 return STATUS_IO_TIMEOUT;
116 }
117
118 /*
119 * This one reads a value from the port; You don't have to specify
120 * which one, it'll always be from the one you talked to, so one function
121 * is enough this time. Note how MSDN specifies the
122 * WaitForAck parameter to be ignored.
123 */
124 NTSTATUS NTAPI
125 i8042SynchReadPort(
126 IN PVOID Context,
127 OUT PUCHAR Value,
128 IN BOOLEAN WaitForAck)
129 {
130 PPORT_DEVICE_EXTENSION DeviceExtension;
131
132 UNREFERENCED_PARAMETER(WaitForAck);
133
134 DeviceExtension = (PPORT_DEVICE_EXTENSION)Context;
135
136 return i8042ReadDataWait(DeviceExtension, Value);
137 }
138
139 /*
140 * These functions are callbacks for filter driver custom
141 * initialization routines.
142 */
143 NTSTATUS NTAPI
144 i8042SynchWritePort(
145 IN PPORT_DEVICE_EXTENSION DeviceExtension,
146 IN UCHAR Port,
147 IN UCHAR Value,
148 IN BOOLEAN WaitForAck)
149 {
150 NTSTATUS Status;
151 UCHAR Ack;
152 ULONG ResendIterations;
153
154 ResendIterations = DeviceExtension->Settings.ResendIterations + 1;
155
156 do
157 {
158 if (Port)
159 if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Port))
160 {
161 WARN_(I8042PRT, "Failed to write Port\n");
162 return STATUS_IO_TIMEOUT;
163 }
164
165 if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
166 {
167 WARN_(I8042PRT, "Failed to write Value\n");
168 return STATUS_IO_TIMEOUT;
169 }
170
171 if (WaitForAck)
172 {
173 Status = i8042ReadDataWait(DeviceExtension, &Ack);
174 if (!NT_SUCCESS(Status))
175 {
176 WARN_(I8042PRT, "Failed to read Ack\n");
177 return Status;
178 }
179 if (Ack == KBD_ACK)
180 return STATUS_SUCCESS;
181 else if (Ack == KBD_RESEND)
182 INFO_(I8042PRT, "i8042 asks for a data resend\n");
183 }
184 else
185 {
186 return STATUS_SUCCESS;
187 }
188 TRACE_(I8042PRT, "Reiterating\n");
189 ResendIterations--;
190 } while (ResendIterations);
191
192 return STATUS_IO_TIMEOUT;
193 }
194
195 /*
196 * FUNCTION: Write data to a port, waiting first for it to become ready
197 */
198 BOOLEAN
199 i8042Write(
200 IN PPORT_DEVICE_EXTENSION DeviceExtension,
201 IN PUCHAR addr,
202 IN UCHAR data)
203 {
204 ULONG Counter;
205
206 ASSERT(addr);
207 ASSERT(DeviceExtension->ControlPort != NULL);
208
209 Counter = DeviceExtension->Settings.PollingIterations;
210
211 while ((KBD_IBF & READ_PORT_UCHAR(DeviceExtension->ControlPort)) &&
212 (Counter--))
213 {
214 KeStallExecutionProcessor(50);
215 }
216
217 if (Counter)
218 {
219 WRITE_PORT_UCHAR(addr, data);
220 INFO_(I8042PRT, "Sent 0x%x to port %p\n", data, addr);
221 return TRUE;
222 }
223 return FALSE;
224 }