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