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