]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / Ps2KeyboardDxe / Ps2Keyboard.c
1 /**@file
2
3 PS/2 Keyboard driver. Routines that interacts with callers,
4 conforming to EFI driver model
5
6 Copyright (c) 2006 - 2007, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Ps2Keyboard.h"
18
19 //
20 // Function prototypes
21 //
22 EFI_STATUS
23 EFIAPI
24 KbdControllerDriverSupported (
25 IN EFI_DRIVER_BINDING_PROTOCOL *This,
26 IN EFI_HANDLE Controller,
27 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
28 );
29
30 EFI_STATUS
31 EFIAPI
32 KbdControllerDriverStart (
33 IN EFI_DRIVER_BINDING_PROTOCOL *This,
34 IN EFI_HANDLE Controller,
35 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
36 );
37
38 EFI_STATUS
39 EFIAPI
40 KbdControllerDriverStop (
41 IN EFI_DRIVER_BINDING_PROTOCOL *This,
42 IN EFI_HANDLE Controller,
43 IN UINTN NumberOfChildren,
44 IN EFI_HANDLE *ChildHandleBuffer
45 );
46
47 EFI_STATUS
48 KbdFreeNotifyList (
49 IN OUT LIST_ENTRY *ListHead
50 );
51
52 //
53 // DriverBinding Protocol Instance
54 //
55 EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver = {
56 KbdControllerDriverSupported,
57 KbdControllerDriverStart,
58 KbdControllerDriverStop,
59 0xa,
60 NULL,
61 NULL
62 };
63
64 /**
65 Test controller is a keyboard Controller
66
67 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
68 @param Controller driver's controller
69 @param RemainingDevicePath children device path
70
71 @retval EFI_UNSUPPORTED controller is not floppy disk
72 @retval EFI_SUCCESS controller is floppy disk
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 EFI_STATUS Status;
83 EFI_ISA_IO_PROTOCOL *IsaIo;
84
85 //
86 // Open the IO Abstraction(s) needed to perform the supported test
87 //
88 Status = gBS->OpenProtocol (
89 Controller,
90 &gEfiIsaIoProtocolGuid,
91 (VOID **) &IsaIo,
92 This->DriverBindingHandle,
93 Controller,
94 EFI_OPEN_PROTOCOL_BY_DRIVER
95 );
96 if (EFI_ERROR (Status)) {
97 return Status;
98 }
99 //
100 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
101 //
102 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
103 Status = EFI_UNSUPPORTED;
104 }
105 //
106 // Close the I/O Abstraction(s) used to perform the supported test
107 //
108 gBS->CloseProtocol (
109 Controller,
110 &gEfiIsaIoProtocolGuid,
111 This->DriverBindingHandle,
112 Controller
113 );
114
115 return Status;
116 }
117
118 /**
119 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
120
121 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
122 @param Controller driver controller handle
123 @param RemainingDevicePath Children's device path
124
125 @retval whether success to create floppy control instance.
126 **/
127 EFI_STATUS
128 EFIAPI
129 KbdControllerDriverStart (
130 IN EFI_DRIVER_BINDING_PROTOCOL *This,
131 IN EFI_HANDLE Controller,
132 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
133 )
134 {
135 EFI_STATUS Status;
136 EFI_STATUS Status1;
137 EFI_ISA_IO_PROTOCOL *IsaIo;
138 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
139 UINT8 Data;
140 EFI_STATUS_CODE_VALUE StatusCode;
141 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
142
143 StatusCode = 0;
144
145 Status = gBS->OpenProtocol (
146 Controller,
147 &gEfiDevicePathProtocolGuid,
148 (VOID **) &ParentDevicePath,
149 This->DriverBindingHandle,
150 Controller,
151 EFI_OPEN_PROTOCOL_BY_DRIVER
152 );
153 if (EFI_ERROR (Status)) {
154 return Status;
155 }
156 //
157 // Report that the keyboard is being enabled
158 //
159 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
160 EFI_PROGRESS_CODE,
161 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,
162 ParentDevicePath
163 );
164
165 //
166 // Get the ISA I/O Protocol on Controller's handle
167 //
168 Status = gBS->OpenProtocol (
169 Controller,
170 &gEfiIsaIoProtocolGuid,
171 (VOID **) &IsaIo,
172 This->DriverBindingHandle,
173 Controller,
174 EFI_OPEN_PROTOCOL_BY_DRIVER
175 );
176 if (EFI_ERROR (Status)) {
177 gBS->CloseProtocol (
178 Controller,
179 &gEfiDevicePathProtocolGuid,
180 This->DriverBindingHandle,
181 Controller
182 );
183 return EFI_INVALID_PARAMETER;
184 }
185 //
186 // Allocate private data
187 //
188 ConsoleIn = AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV));
189 if (ConsoleIn == NULL) {
190 Status = EFI_OUT_OF_RESOURCES;
191 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
192 goto ErrorExit;
193 }
194 //
195 // Setup the device instance
196 //
197 ConsoleIn->Signature = KEYBOARD_CONSOLE_IN_DEV_SIGNATURE;
198 ConsoleIn->Handle = Controller;
199 (ConsoleIn->ConIn).Reset = KeyboardEfiReset;
200 (ConsoleIn->ConIn).ReadKeyStroke = KeyboardReadKeyStroke;
201 ConsoleIn->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;
202 ConsoleIn->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;
203 ConsoleIn->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
204 ConsoleIn->IsaIo = IsaIo;
205 ConsoleIn->ScancodeBufStartPos = 0;
206 ConsoleIn->ScancodeBufEndPos = KEYBOARD_BUFFER_MAX_COUNT - 1;
207 ConsoleIn->ScancodeBufCount = 0;
208 ConsoleIn->Ctrled = FALSE;
209 ConsoleIn->Alted = FALSE;
210 ConsoleIn->DevicePath = ParentDevicePath;
211
212 ConsoleIn->ConInEx.Reset = KeyboardEfiResetEx;
213 ConsoleIn->ConInEx.ReadKeyStrokeEx = KeyboardReadKeyStrokeEx;
214 ConsoleIn->ConInEx.SetState = KeyboardSetState;
215 ConsoleIn->ConInEx.RegisterKeyNotify = KeyboardRegisterKeyNotify;
216 ConsoleIn->ConInEx.UnregisterKeyNotify = KeyboardUnregisterKeyNotify;
217
218 InitializeListHead (&ConsoleIn->NotifyList);
219 //
220 // Setup the WaitForKey event
221 //
222 Status = gBS->CreateEvent (
223 EVT_NOTIFY_WAIT,
224 TPL_NOTIFY,
225 KeyboardWaitForKey,
226 &(ConsoleIn->ConIn),
227 &((ConsoleIn->ConIn).WaitForKey)
228 );
229 if (EFI_ERROR (Status)) {
230 Status = EFI_OUT_OF_RESOURCES;
231 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
232 goto ErrorExit;
233 }
234 //
235 // Setup the WaitForKeyEx event
236 //
237 Status = gBS->CreateEvent (
238 EVT_NOTIFY_WAIT,
239 TPL_NOTIFY,
240 KeyboardWaitForKeyEx,
241 &(ConsoleIn->ConInEx),
242 &(ConsoleIn->ConInEx.WaitForKeyEx)
243 );
244 if (EFI_ERROR (Status)) {
245 Status = EFI_OUT_OF_RESOURCES;
246 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
247 goto ErrorExit;
248 }
249 // Setup a periodic timer, used for reading keystrokes at a fixed interval
250 //
251 Status = gBS->CreateEvent (
252 EVT_TIMER | EVT_NOTIFY_SIGNAL,
253 TPL_NOTIFY,
254 KeyboardTimerHandler,
255 ConsoleIn,
256 &ConsoleIn->TimerEvent
257 );
258 if (EFI_ERROR (Status)) {
259 Status = EFI_OUT_OF_RESOURCES;
260 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
261 goto ErrorExit;
262 }
263
264 Status = gBS->SetTimer (
265 ConsoleIn->TimerEvent,
266 TimerPeriodic,
267 KEYBOARD_TIMER_INTERVAL
268 );
269 if (EFI_ERROR (Status)) {
270 Status = EFI_OUT_OF_RESOURCES;
271 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
272 goto ErrorExit;
273 }
274
275 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
276 EFI_PROGRESS_CODE,
277 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,
278 ParentDevicePath
279 );
280
281 //
282 // Reset the keyboard device
283 //
284 Status = ConsoleIn->ConIn.Reset (&ConsoleIn->ConIn, TRUE);
285 if (EFI_ERROR (Status)) {
286 Status = EFI_DEVICE_ERROR;
287 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
288 goto ErrorExit;
289 }
290
291 ConsoleIn->ControllerNameTable = NULL;
292 AddUnicodeString2 (
293 "eng",
294 gPs2KeyboardComponentName.SupportedLanguages,
295 &ConsoleIn->ControllerNameTable,
296 L"PS/2 Keyboard Device",
297 TRUE
298 );
299 AddUnicodeString2 (
300 "en",
301 gPs2KeyboardComponentName2.SupportedLanguages,
302 &ConsoleIn->ControllerNameTable,
303 L"PS/2 Keyboard Device",
304 FALSE
305 );
306
307
308 //
309 // Install protocol interfaces for the keyboard device.
310 //
311 Status = gBS->InstallMultipleProtocolInterfaces (
312 &Controller,
313 &gEfiSimpleTextInProtocolGuid,
314 &ConsoleIn->ConIn,
315 &gEfiSimpleTextInputExProtocolGuid,
316 &ConsoleIn->ConInEx,
317 NULL
318 );
319 if (EFI_ERROR (Status)) {
320 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
321 goto ErrorExit;
322 }
323
324 return Status;
325
326 ErrorExit:
327 //
328 // Report error code
329 //
330 if (StatusCode != 0) {
331 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
332 EFI_ERROR_CODE | EFI_ERROR_MINOR,
333 StatusCode,
334 ParentDevicePath
335 );
336 }
337
338 if ((ConsoleIn != NULL) && (ConsoleIn->ConIn.WaitForKey != NULL)) {
339 gBS->CloseEvent (ConsoleIn->ConIn.WaitForKey);
340 }
341
342 if ((ConsoleIn != NULL) && (ConsoleIn->TimerEvent != NULL)) {
343 gBS->CloseEvent (ConsoleIn->TimerEvent);
344 }
345 if ((ConsoleIn != NULL) && (ConsoleIn->ConInEx.WaitForKeyEx != NULL)) {
346 gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
347 }
348 KbdFreeNotifyList (&ConsoleIn->NotifyList);
349 if ((ConsoleIn != NULL) && (ConsoleIn->ControllerNameTable != NULL)) {
350 FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
351 }
352 //
353 // Since there will be no timer handler for keyboard input any more,
354 // exhaust input data just in case there is still keyboard data left
355 //
356 Status1 = EFI_SUCCESS;
357 while (!EFI_ERROR (Status1)) {
358 Status1 = KeyboardRead (ConsoleIn, &Data);;
359 }
360
361 if (ConsoleIn != NULL) {
362 gBS->FreePool (ConsoleIn);
363 }
364
365 gBS->CloseProtocol (
366 Controller,
367 &gEfiDevicePathProtocolGuid,
368 This->DriverBindingHandle,
369 Controller
370 );
371
372 gBS->CloseProtocol (
373 Controller,
374 &gEfiIsaIoProtocolGuid,
375 This->DriverBindingHandle,
376 Controller
377 );
378
379 return Status;
380 }
381
382 /**
383 Stop this driver on ControllerHandle. Support stoping any child handles
384 created by this driver.
385
386 @param This Protocol instance pointer.
387 @param ControllerHandle Handle of device to stop driver on
388 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
389 children is zero stop the entire bus driver.
390 @param ChildHandleBuffer List of Child Handles to Stop.
391
392 @retval EFI_SUCCESS This driver is removed ControllerHandle
393 @retval other This driver was not removed from this device
394
395 **/
396 EFI_STATUS
397 EFIAPI
398 KbdControllerDriverStop (
399 IN EFI_DRIVER_BINDING_PROTOCOL *This,
400 IN EFI_HANDLE Controller,
401 IN UINTN NumberOfChildren,
402 IN EFI_HANDLE *ChildHandleBuffer
403 )
404 {
405 EFI_STATUS Status;
406 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
407 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
408 UINT8 Data;
409
410 //
411 // Disable Keyboard
412 //
413 Status = gBS->OpenProtocol (
414 Controller,
415 &gEfiSimpleTextInProtocolGuid,
416 (VOID **) &ConIn,
417 This->DriverBindingHandle,
418 Controller,
419 EFI_OPEN_PROTOCOL_GET_PROTOCOL
420 );
421 if (EFI_ERROR (Status)) {
422 return Status;
423 }
424 Status = gBS->OpenProtocol (
425 Controller,
426 &gEfiSimpleTextInputExProtocolGuid,
427 NULL,
428 This->DriverBindingHandle,
429 Controller,
430 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
431 );
432 if (EFI_ERROR (Status)) {
433 return Status;
434 }
435
436 ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn);
437
438 //
439 // Report that the keyboard is being disabled
440 //
441 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
442 EFI_PROGRESS_CODE,
443 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE,
444 ConsoleIn->DevicePath
445 );
446
447 if (ConsoleIn->TimerEvent) {
448 gBS->CloseEvent (ConsoleIn->TimerEvent);
449 ConsoleIn->TimerEvent = NULL;
450 }
451 //
452 // Disable the keyboard interface
453 //
454 Status = DisableKeyboard (ConsoleIn);
455
456 //
457 // Since there will be no timer handler for keyboard input any more,
458 // exhaust input data just in case there is still keyboard data left
459 //
460 Status = EFI_SUCCESS;
461 while (!EFI_ERROR (Status)) {
462 Status = KeyboardRead (ConsoleIn, &Data);;
463 }
464 //
465 // Uninstall the SimpleTextIn and SimpleTextInEx protocols
466 //
467 Status = gBS->UninstallMultipleProtocolInterfaces (
468 Controller,
469 &gEfiSimpleTextInProtocolGuid,
470 &ConsoleIn->ConIn,
471 &gEfiSimpleTextInputExProtocolGuid,
472 &ConsoleIn->ConInEx,
473 NULL
474 );
475 if (EFI_ERROR (Status)) {
476 return Status;
477 }
478
479 gBS->CloseProtocol (
480 Controller,
481 &gEfiDevicePathProtocolGuid,
482 This->DriverBindingHandle,
483 Controller
484 );
485
486 gBS->CloseProtocol (
487 Controller,
488 &gEfiIsaIoProtocolGuid,
489 This->DriverBindingHandle,
490 Controller
491 );
492
493 //
494 // Free other resources
495 //
496 if ((ConsoleIn->ConIn).WaitForKey) {
497 gBS->CloseEvent ((ConsoleIn->ConIn).WaitForKey);
498 (ConsoleIn->ConIn).WaitForKey = NULL;
499 }
500 if (ConsoleIn->ConInEx.WaitForKeyEx != NULL) {
501 gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
502 ConsoleIn->ConInEx.WaitForKeyEx = NULL;
503 }
504 KbdFreeNotifyList (&ConsoleIn->NotifyList);
505 FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
506 gBS->FreePool (ConsoleIn);
507
508 return EFI_SUCCESS;
509 }
510
511 /**
512 Free the waiting key notify list.
513
514 @param ListHead Pointer to list head
515 **/
516 EFI_STATUS
517 KbdFreeNotifyList (
518 IN OUT LIST_ENTRY *ListHead
519 )
520 {
521 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
522
523 if (ListHead == NULL) {
524 return EFI_INVALID_PARAMETER;
525 }
526 while (!IsListEmpty (ListHead)) {
527 NotifyNode = CR (
528 ListHead->ForwardLink,
529 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
530 NotifyEntry,
531 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
532 );
533 RemoveEntryList (ListHead->ForwardLink);
534 gBS->FreePool (NotifyNode);
535 }
536
537 return EFI_SUCCESS;
538 }
539
540 /**
541 The user Entry Point for module Ps2Keyboard. The user code starts with this function.
542
543 @param[in] ImageHandle The firmware allocated handle for the EFI image.
544 @param[in] SystemTable A pointer to the EFI System Table.
545
546 @retval EFI_SUCCESS The entry point is executed successfully.
547 @retval other Some error occurs when executing this entry point.
548
549 **/
550 EFI_STATUS
551 EFIAPI
552 InitializePs2Keyboard(
553 IN EFI_HANDLE ImageHandle,
554 IN EFI_SYSTEM_TABLE *SystemTable
555 )
556 {
557 EFI_STATUS Status;
558
559 //
560 // Install driver model protocol(s).
561 //
562 Status = EfiLibInstallDriverBindingComponentName2 (
563 ImageHandle,
564 SystemTable,
565 &gKeyboardControllerDriver,
566 ImageHandle,
567 &gPs2KeyboardComponentName,
568 &gPs2KeyboardComponentName2
569 );
570 ASSERT_EFI_ERROR (Status);
571
572
573 return Status;
574 }
575