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