Update to BSD license header.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / Ps2KeyboardDxe / Ps2Keyboard.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Ps2Keyboard.c
15
16 Abstract:
17
18 PS/2 Keyboard driver. Routines that interacts with callers,
19 conforming to EFI driver model
20
21 --*/
22
23 //
24 // Include common header file for this module.
25 //
26 #include "CommonHeader.h"
27
28 #include "Ps2Keyboard.h"
29
30 //
31 // Function prototypes
32 //
33 EFI_STATUS
34 EFIAPI
35 KbdControllerDriverSupported (
36 IN EFI_DRIVER_BINDING_PROTOCOL *This,
37 IN EFI_HANDLE Controller,
38 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
39 );
40
41 EFI_STATUS
42 EFIAPI
43 KbdControllerDriverStart (
44 IN EFI_DRIVER_BINDING_PROTOCOL *This,
45 IN EFI_HANDLE Controller,
46 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
47 );
48
49 EFI_STATUS
50 EFIAPI
51 KbdControllerDriverStop (
52 IN EFI_DRIVER_BINDING_PROTOCOL *This,
53 IN EFI_HANDLE Controller,
54 IN UINTN NumberOfChildren,
55 IN EFI_HANDLE *ChildHandleBuffer
56 );
57
58 //
59 // Global variables
60 //
61 //
62 // DriverBinding Protocol Instance
63 //
64 EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver = {
65 KbdControllerDriverSupported,
66 KbdControllerDriverStart,
67 KbdControllerDriverStop,
68 0xa,
69 NULL,
70 NULL
71 };
72
73 EFI_STATUS
74 EFIAPI
75 KbdControllerDriverSupported (
76 IN EFI_DRIVER_BINDING_PROTOCOL *This,
77 IN EFI_HANDLE Controller,
78 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
79 )
80 /*++
81
82 Routine Description:
83
84 ControllerDriver Protocol Method
85
86 Arguments:
87
88 Returns:
89
90 --*/
91 // GC_TODO: This - add argument and description to function comment
92 // GC_TODO: Controller - add argument and description to function comment
93 // GC_TODO: RemainingDevicePath - add argument and description to function comment
94 {
95 EFI_STATUS Status;
96 EFI_ISA_IO_PROTOCOL *IsaIo;
97
98 //
99 // Open the IO Abstraction(s) needed to perform the supported test
100 //
101 Status = gBS->OpenProtocol (
102 Controller,
103 &gEfiIsaIoProtocolGuid,
104 (VOID **) &IsaIo,
105 This->DriverBindingHandle,
106 Controller,
107 EFI_OPEN_PROTOCOL_BY_DRIVER
108 );
109 if (EFI_ERROR (Status)) {
110 return Status;
111 }
112 //
113 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
114 //
115 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
116 Status = EFI_UNSUPPORTED;
117 }
118 //
119 // Close the I/O Abstraction(s) used to perform the supported test
120 //
121 gBS->CloseProtocol (
122 Controller,
123 &gEfiIsaIoProtocolGuid,
124 This->DriverBindingHandle,
125 Controller
126 );
127
128 return Status;
129 }
130
131 EFI_STATUS
132 EFIAPI
133 KbdControllerDriverStart (
134 IN EFI_DRIVER_BINDING_PROTOCOL *This,
135 IN EFI_HANDLE Controller,
136 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
137 )
138 /*++
139
140 Routine Description:
141
142 Arguments:
143
144 Returns:
145
146 --*/
147 // GC_TODO: This - add argument and description to function comment
148 // GC_TODO: Controller - add argument and description to function comment
149 // GC_TODO: RemainingDevicePath - add argument and description to function comment
150 // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
151 {
152 EFI_STATUS Status;
153 EFI_STATUS Status1;
154 EFI_ISA_IO_PROTOCOL *IsaIo;
155 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
156 UINT8 Data;
157 EFI_STATUS_CODE_VALUE StatusCode;
158 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
159
160 StatusCode = 0;
161
162 Status = gBS->OpenProtocol (
163 Controller,
164 &gEfiDevicePathProtocolGuid,
165 (VOID **) &ParentDevicePath,
166 This->DriverBindingHandle,
167 Controller,
168 EFI_OPEN_PROTOCOL_BY_DRIVER
169 );
170 if (EFI_ERROR (Status)) {
171 return Status;
172 }
173 //
174 // Report that the keyboard is being enabled
175 //
176 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
177 EFI_PROGRESS_CODE,
178 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,
179 ParentDevicePath
180 );
181
182 //
183 // Get the ISA I/O Protocol on Controller's handle
184 //
185 Status = gBS->OpenProtocol (
186 Controller,
187 &gEfiIsaIoProtocolGuid,
188 (VOID **) &IsaIo,
189 This->DriverBindingHandle,
190 Controller,
191 EFI_OPEN_PROTOCOL_BY_DRIVER
192 );
193 if (EFI_ERROR (Status)) {
194 gBS->CloseProtocol (
195 Controller,
196 &gEfiDevicePathProtocolGuid,
197 This->DriverBindingHandle,
198 Controller
199 );
200 return EFI_INVALID_PARAMETER;
201 }
202 //
203 // Allocate private data
204 //
205 ConsoleIn = AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV));
206 if (ConsoleIn == NULL) {
207 Status = EFI_OUT_OF_RESOURCES;
208 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
209 goto ErrorExit;
210 }
211 //
212 // Setup the device instance
213 //
214 ConsoleIn->Signature = KEYBOARD_CONSOLE_IN_DEV_SIGNATURE;
215 ConsoleIn->Handle = Controller;
216 (ConsoleIn->ConIn).Reset = KeyboardEfiReset;
217 (ConsoleIn->ConIn).ReadKeyStroke = KeyboardReadKeyStroke;
218 ConsoleIn->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;
219 ConsoleIn->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;
220 ConsoleIn->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
221 ConsoleIn->IsaIo = IsaIo;
222 ConsoleIn->ScancodeBufStartPos = 0;
223 ConsoleIn->ScancodeBufEndPos = KEYBOARD_BUFFER_MAX_COUNT - 1;
224 ConsoleIn->ScancodeBufCount = 0;
225 ConsoleIn->Ctrled = FALSE;
226 ConsoleIn->Alted = FALSE;
227 ConsoleIn->DevicePath = ParentDevicePath;
228
229 //
230 // Setup the WaitForKey event
231 //
232 Status = gBS->CreateEvent (
233 EVT_NOTIFY_WAIT,
234 TPL_NOTIFY,
235 KeyboardWaitForKey,
236 &(ConsoleIn->ConIn),
237 &((ConsoleIn->ConIn).WaitForKey)
238 );
239 if (EFI_ERROR (Status)) {
240 Status = EFI_OUT_OF_RESOURCES;
241 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
242 goto ErrorExit;
243 }
244 //
245 // Setup a periodic timer, used for reading keystrokes at a fixed interval
246 //
247 Status = gBS->CreateEvent (
248 EVT_TIMER | EVT_NOTIFY_SIGNAL,
249 TPL_NOTIFY,
250 KeyboardTimerHandler,
251 ConsoleIn,
252 &ConsoleIn->TimerEvent
253 );
254 if (EFI_ERROR (Status)) {
255 Status = EFI_OUT_OF_RESOURCES;
256 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
257 goto ErrorExit;
258 }
259
260 Status = gBS->SetTimer (
261 ConsoleIn->TimerEvent,
262 TimerPeriodic,
263 KEYBOARD_TIMER_INTERVAL
264 );
265 if (EFI_ERROR (Status)) {
266 Status = EFI_OUT_OF_RESOURCES;
267 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
268 goto ErrorExit;
269 }
270
271 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
272 EFI_PROGRESS_CODE,
273 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,
274 ParentDevicePath
275 );
276
277 //
278 // Reset the keyboard device
279 //
280 Status = ConsoleIn->ConIn.Reset (&ConsoleIn->ConIn, TRUE);
281 if (EFI_ERROR (Status)) {
282 Status = EFI_DEVICE_ERROR;
283 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
284 goto ErrorExit;
285 }
286
287 ConsoleIn->ControllerNameTable = NULL;
288 AddUnicodeString (
289 "eng",
290 gPs2KeyboardComponentName.SupportedLanguages,
291 &ConsoleIn->ControllerNameTable,
292 L"PS/2 Keyboard Device"
293 );
294
295 //
296 // Install protocol interfaces for the keyboard device.
297 //
298 Status = gBS->InstallMultipleProtocolInterfaces (
299 &Controller,
300 &gEfiSimpleTextInProtocolGuid,
301 &ConsoleIn->ConIn,
302 NULL
303 );
304 if (EFI_ERROR (Status)) {
305 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
306 goto ErrorExit;
307 }
308
309 return Status;
310
311 ErrorExit:
312 //
313 // Report error code
314 //
315 if (StatusCode != 0) {
316 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
317 EFI_ERROR_CODE | EFI_ERROR_MINOR,
318 StatusCode,
319 ParentDevicePath
320 );
321 }
322
323 if ((ConsoleIn != NULL) && (ConsoleIn->ConIn.WaitForKey != NULL)) {
324 gBS->CloseEvent (ConsoleIn->ConIn.WaitForKey);
325 }
326
327 if ((ConsoleIn != NULL) && (ConsoleIn->TimerEvent != NULL)) {
328 gBS->CloseEvent (ConsoleIn->TimerEvent);
329 }
330
331 if ((ConsoleIn != NULL) && (ConsoleIn->ControllerNameTable != NULL)) {
332 FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
333 }
334 //
335 // Since there will be no timer handler for keyboard input any more,
336 // exhaust input data just in case there is still keyboard data left
337 //
338 Status1 = EFI_SUCCESS;
339 while (!EFI_ERROR (Status1)) {
340 Status1 = KeyboardRead (ConsoleIn, &Data);;
341 }
342
343 if (ConsoleIn != NULL) {
344 gBS->FreePool (ConsoleIn);
345 }
346
347 gBS->CloseProtocol (
348 Controller,
349 &gEfiDevicePathProtocolGuid,
350 This->DriverBindingHandle,
351 Controller
352 );
353
354 gBS->CloseProtocol (
355 Controller,
356 &gEfiIsaIoProtocolGuid,
357 This->DriverBindingHandle,
358 Controller
359 );
360
361 return Status;
362 }
363
364 EFI_STATUS
365 EFIAPI
366 KbdControllerDriverStop (
367 IN EFI_DRIVER_BINDING_PROTOCOL *This,
368 IN EFI_HANDLE Controller,
369 IN UINTN NumberOfChildren,
370 IN EFI_HANDLE *ChildHandleBuffer
371 )
372 /*++
373
374 Routine Description:
375
376 Arguments:
377
378 Returns:
379
380 --*/
381 // GC_TODO: This - add argument and description to function comment
382 // GC_TODO: Controller - add argument and description to function comment
383 // GC_TODO: NumberOfChildren - add argument and description to function comment
384 // GC_TODO: ChildHandleBuffer - add argument and description to function comment
385 // GC_TODO: EFI_SUCCESS - add return value to function comment
386 {
387 EFI_STATUS Status;
388 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
389 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
390 UINT8 Data;
391
392 //
393 // Disable Keyboard
394 //
395 Status = gBS->OpenProtocol (
396 Controller,
397 &gEfiSimpleTextInProtocolGuid,
398 (VOID **) &ConIn,
399 This->DriverBindingHandle,
400 Controller,
401 EFI_OPEN_PROTOCOL_GET_PROTOCOL
402 );
403 if (EFI_ERROR (Status)) {
404 return Status;
405 }
406
407 ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn);
408
409 //
410 // Report that the keyboard is being disabled
411 //
412 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
413 EFI_PROGRESS_CODE,
414 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE,
415 ConsoleIn->DevicePath
416 );
417
418 if (ConsoleIn->TimerEvent) {
419 gBS->CloseEvent (ConsoleIn->TimerEvent);
420 ConsoleIn->TimerEvent = NULL;
421 }
422 //
423 // Disable the keyboard interface
424 //
425 Status = DisableKeyboard (ConsoleIn);
426
427 //
428 // Since there will be no timer handler for keyboard input any more,
429 // exhaust input data just in case there is still keyboard data left
430 //
431 Status = EFI_SUCCESS;
432 while (!EFI_ERROR (Status)) {
433 Status = KeyboardRead (ConsoleIn, &Data);;
434 }
435 //
436 // Uninstall the Simple TextIn Protocol
437 //
438 Status = gBS->UninstallProtocolInterface (
439 Controller,
440 &gEfiSimpleTextInProtocolGuid,
441 &ConsoleIn->ConIn
442 );
443 if (EFI_ERROR (Status)) {
444 return Status;
445 }
446
447 gBS->CloseProtocol (
448 Controller,
449 &gEfiDevicePathProtocolGuid,
450 This->DriverBindingHandle,
451 Controller
452 );
453
454 gBS->CloseProtocol (
455 Controller,
456 &gEfiIsaIoProtocolGuid,
457 This->DriverBindingHandle,
458 Controller
459 );
460
461 //
462 // Free other resources
463 //
464 if ((ConsoleIn->ConIn).WaitForKey) {
465 gBS->CloseEvent ((ConsoleIn->ConIn).WaitForKey);
466 (ConsoleIn->ConIn).WaitForKey = NULL;
467 }
468
469 FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
470 gBS->FreePool (ConsoleIn);
471
472 return EFI_SUCCESS;
473 }