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