]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[mirror_edk2.git] / EdkModulePkg / Bus / Usb / UsbKb / Dxe / efikey.c
1 /*++
2
3 Copyright (c) 2006, 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 EfiKey.c
15
16 Abstract:
17
18 USB Keyboard Driver
19
20 Revision History
21
22 --*/
23
24 #include "efikey.h"
25 #include "keyboard.h"
26
27 //
28 // Prototypes
29 // Driver model protocol interface
30 //
31 EFI_STATUS
32 EFIAPI
33 USBKeyboardDriverBindingEntryPoint (
34 IN EFI_HANDLE ImageHandle,
35 IN EFI_SYSTEM_TABLE *SystemTable
36 );
37
38 EFI_STATUS
39 EFIAPI
40 USBKeyboardDriverBindingSupported (
41 IN EFI_DRIVER_BINDING_PROTOCOL *This,
42 IN EFI_HANDLE Controller,
43 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
44 );
45
46 EFI_STATUS
47 EFIAPI
48 USBKeyboardDriverBindingStart (
49 IN EFI_DRIVER_BINDING_PROTOCOL *This,
50 IN EFI_HANDLE Controller,
51 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
52 );
53
54 EFI_STATUS
55 EFIAPI
56 USBKeyboardDriverBindingStop (
57 IN EFI_DRIVER_BINDING_PROTOCOL *This,
58 IN EFI_HANDLE Controller,
59 IN UINTN NumberOfChildren,
60 IN EFI_HANDLE *ChildHandleBuffer
61 );
62
63 //
64 // Simple Text In Protocol Interface
65 //
66 STATIC
67 EFI_STATUS
68 EFIAPI
69 USBKeyboardReset (
70 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,
71 IN BOOLEAN ExtendedVerification
72 );
73
74 STATIC
75 EFI_STATUS
76 EFIAPI
77 USBKeyboardReadKeyStroke (
78 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,
79 OUT EFI_INPUT_KEY *Key
80 );
81
82 STATIC
83 VOID
84 EFIAPI
85 USBKeyboardWaitForKey (
86 IN EFI_EVENT Event,
87 IN VOID *Context
88 );
89
90 //
91 // Helper functions
92 //
93 STATIC
94 EFI_STATUS
95 USBKeyboardCheckForKey (
96 IN USB_KB_DEV *UsbKeyboardDevice
97 );
98
99 //
100 // USB Keyboard Driver Global Variables
101 //
102 EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = {
103 USBKeyboardDriverBindingSupported,
104 USBKeyboardDriverBindingStart,
105 USBKeyboardDriverBindingStop,
106 0xa,
107 NULL,
108 NULL
109 };
110
111 EFI_STATUS
112 EFIAPI
113 USBKeyboardDriverBindingSupported (
114 IN EFI_DRIVER_BINDING_PROTOCOL *This,
115 IN EFI_HANDLE Controller,
116 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
117 )
118 /*++
119
120 Routine Description:
121 Supported.
122
123 Arguments:
124 This - EFI_DRIVER_BINDING_PROTOCOL
125 Controller - Controller handle
126 RemainingDevicePath - EFI_DEVICE_PATH_PROTOCOL
127 Returns:
128 EFI_STATUS
129
130 --*/
131 {
132 EFI_STATUS OpenStatus;
133 EFI_USB_IO_PROTOCOL *UsbIo;
134 EFI_STATUS Status;
135
136 //
137 // Check if USB_IO protocol is attached on the controller handle.
138 //
139 OpenStatus = gBS->OpenProtocol (
140 Controller,
141 &gEfiUsbIoProtocolGuid,
142 (VOID **) &UsbIo,
143 This->DriverBindingHandle,
144 Controller,
145 EFI_OPEN_PROTOCOL_BY_DRIVER
146 );
147 if (EFI_ERROR (OpenStatus)) {
148 return OpenStatus;
149 }
150
151 //
152 // Use the USB I/O protocol interface to check whether the Controller is
153 // the Keyboard controller that can be managed by this driver.
154 //
155 Status = EFI_SUCCESS;
156
157 if (!IsUSBKeyboard (UsbIo)) {
158 Status = EFI_UNSUPPORTED;
159 }
160
161 gBS->CloseProtocol (
162 Controller,
163 &gEfiUsbIoProtocolGuid,
164 This->DriverBindingHandle,
165 Controller
166 );
167
168 return Status;
169 }
170
171 EFI_STATUS
172 EFIAPI
173 USBKeyboardDriverBindingStart (
174 IN EFI_DRIVER_BINDING_PROTOCOL *This,
175 IN EFI_HANDLE Controller,
176 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
177 )
178 /*++
179
180 Routine Description:
181 Start.
182
183 Arguments:
184 This - EFI_DRIVER_BINDING_PROTOCOL
185 Controller - Controller handle
186 RemainingDevicePath - EFI_DEVICE_PATH_PROTOCOL
187 Returns:
188 EFI_SUCCESS - Success
189 EFI_OUT_OF_RESOURCES - Can't allocate memory
190 EFI_UNSUPPORTED - The Start routine fail
191 --*/
192 {
193 EFI_STATUS Status;
194 EFI_USB_IO_PROTOCOL *UsbIo;
195 USB_KB_DEV *UsbKeyboardDevice;
196 UINT8 EndpointNumber;
197 EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
198 UINT8 Index;
199 UINT8 EndpointAddr;
200 UINT8 PollingInterval;
201 UINT8 PacketSize;
202 BOOLEAN Found;
203
204 UsbKeyboardDevice = NULL;
205 Found = FALSE;
206
207 //
208 // Open USB_IO Protocol
209 //
210 Status = gBS->OpenProtocol (
211 Controller,
212 &gEfiUsbIoProtocolGuid,
213 (VOID **) &UsbIo,
214 This->DriverBindingHandle,
215 Controller,
216 EFI_OPEN_PROTOCOL_BY_DRIVER
217 );
218 if (EFI_ERROR (Status)) {
219 return Status;
220 }
221
222 UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV));
223 if (UsbKeyboardDevice == NULL) {
224 gBS->CloseProtocol (
225 Controller,
226 &gEfiUsbIoProtocolGuid,
227 This->DriverBindingHandle,
228 Controller
229 );
230 return EFI_OUT_OF_RESOURCES;
231 }
232 //
233 // Get the Device Path Protocol on Controller's handle
234 //
235 Status = gBS->OpenProtocol (
236 Controller,
237 &gEfiDevicePathProtocolGuid,
238 (VOID **) &UsbKeyboardDevice->DevicePath,
239 This->DriverBindingHandle,
240 Controller,
241 EFI_OPEN_PROTOCOL_GET_PROTOCOL
242 );
243
244 if (EFI_ERROR (Status)) {
245 gBS->FreePool (UsbKeyboardDevice);
246 gBS->CloseProtocol (
247 Controller,
248 &gEfiUsbIoProtocolGuid,
249 This->DriverBindingHandle,
250 Controller
251 );
252 return Status;
253 }
254 //
255 // Report that the usb keyboard is being enabled
256 //
257 KbdReportStatusCode (
258 UsbKeyboardDevice->DevicePath,
259 EFI_PROGRESS_CODE,
260 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE)
261 );
262
263 //
264 // This is pretty close to keyboard detection, so log progress
265 //
266 KbdReportStatusCode (
267 UsbKeyboardDevice->DevicePath,
268 EFI_PROGRESS_CODE,
269 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT)
270 );
271
272 //
273 // Initialize UsbKeyboardDevice
274 //
275 UsbKeyboardDevice->UsbIo = UsbIo;
276
277 //
278 // Get interface & endpoint descriptor
279 //
280 UsbIo->UsbGetInterfaceDescriptor (
281 UsbIo,
282 &UsbKeyboardDevice->InterfaceDescriptor
283 );
284
285 EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;
286
287 for (Index = 0; Index < EndpointNumber; Index++) {
288
289 UsbIo->UsbGetEndpointDescriptor (
290 UsbIo,
291 Index,
292 &EndpointDescriptor
293 );
294
295 if ((EndpointDescriptor.Attributes & 0x03) == 0x03) {
296 //
297 // We only care interrupt endpoint here
298 //
299 CopyMem (&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
300 Found = TRUE;
301 }
302 }
303
304 if (!Found) {
305 //
306 // No interrupt endpoint found, then return unsupported.
307 //
308 gBS->FreePool (UsbKeyboardDevice);
309 gBS->CloseProtocol (
310 Controller,
311 &gEfiUsbIoProtocolGuid,
312 This->DriverBindingHandle,
313 Controller
314 );
315 return EFI_UNSUPPORTED;
316 }
317
318 UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE;
319 UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset;
320 UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke;
321 Status = gBS->CreateEvent (
322 EFI_EVENT_NOTIFY_WAIT,
323 EFI_TPL_NOTIFY,
324 USBKeyboardWaitForKey,
325 UsbKeyboardDevice,
326 &(UsbKeyboardDevice->SimpleInput.WaitForKey)
327 );
328
329 if (EFI_ERROR (Status)) {
330 gBS->FreePool (UsbKeyboardDevice);
331 gBS->CloseProtocol (
332 Controller,
333 &gEfiUsbIoProtocolGuid,
334 This->DriverBindingHandle,
335 Controller
336 );
337 return Status;
338 }
339
340 //
341 // Install simple txt in protocol interface
342 // for the usb keyboard device.
343 // Usb keyboard is a hot plug device, and expected to work immediately
344 // when plugging into system, so a HotPlugDeviceGuid is installed onto
345 // the usb keyboard device handle, to distinguish it from other conventional
346 // console devices.
347 //
348 Status = gBS->InstallMultipleProtocolInterfaces (
349 &Controller,
350 &gEfiSimpleTextInProtocolGuid,
351 &UsbKeyboardDevice->SimpleInput,
352 &gEfiHotPlugDeviceGuid,
353 NULL,
354 NULL
355 );
356 if (EFI_ERROR (Status)) {
357 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
358 gBS->FreePool (UsbKeyboardDevice);
359 gBS->CloseProtocol (
360 Controller,
361 &gEfiUsbIoProtocolGuid,
362 This->DriverBindingHandle,
363 Controller
364 );
365 return Status;
366 }
367
368 //
369 // Reset USB Keyboard Device
370 //
371 Status = UsbKeyboardDevice->SimpleInput.Reset (
372 &UsbKeyboardDevice->SimpleInput,
373 TRUE
374 );
375 if (EFI_ERROR (Status)) {
376 gBS->UninstallMultipleProtocolInterfaces (
377 Controller,
378 &gEfiSimpleTextInProtocolGuid,
379 &UsbKeyboardDevice->SimpleInput,
380 &gEfiHotPlugDeviceGuid,
381 NULL,
382 NULL
383 );
384 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
385 gBS->FreePool (UsbKeyboardDevice);
386 gBS->CloseProtocol (
387 Controller,
388 &gEfiUsbIoProtocolGuid,
389 This->DriverBindingHandle,
390 Controller
391 );
392 return Status;
393 }
394 //
395 // submit async interrupt transfer
396 //
397 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
398 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
399 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
400
401 Status = UsbIo->UsbAsyncInterruptTransfer (
402 UsbIo,
403 EndpointAddr,
404 TRUE,
405 PollingInterval,
406 PacketSize,
407 KeyboardHandler,
408 UsbKeyboardDevice
409 );
410
411 if (EFI_ERROR (Status)) {
412
413 gBS->UninstallMultipleProtocolInterfaces (
414 Controller,
415 &gEfiSimpleTextInProtocolGuid,
416 &UsbKeyboardDevice->SimpleInput,
417 &gEfiHotPlugDeviceGuid,
418 NULL,
419 NULL
420 );
421 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
422 gBS->FreePool (UsbKeyboardDevice);
423 gBS->CloseProtocol (
424 Controller,
425 &gEfiUsbIoProtocolGuid,
426 This->DriverBindingHandle,
427 Controller
428 );
429 return Status;
430 }
431
432 UsbKeyboardDevice->ControllerNameTable = NULL;
433 AddUnicodeString (
434 "eng",
435 gUsbKeyboardComponentName.SupportedLanguages,
436 &UsbKeyboardDevice->ControllerNameTable,
437 (CHAR16 *) L"Generic Usb Keyboard"
438 );
439
440 return EFI_SUCCESS;
441 }
442
443
444 EFI_STATUS
445 EFIAPI
446 USBKeyboardDriverBindingStop (
447 IN EFI_DRIVER_BINDING_PROTOCOL *This,
448 IN EFI_HANDLE Controller,
449 IN UINTN NumberOfChildren,
450 IN EFI_HANDLE *ChildHandleBuffer
451 )
452 /*++
453
454 Routine Description:
455 Stop.
456
457 Arguments:
458 This - EFI_DRIVER_BINDING_PROTOCOL
459 Controller - Controller handle
460 NumberOfChildren - Child handle number
461 ChildHandleBuffer - Child handle buffer
462 Returns:
463 EFI_SUCCESS - Success
464 EFI_UNSUPPORTED - Can't support
465 --*/
466 {
467 EFI_STATUS Status;
468 EFI_SIMPLE_TEXT_IN_PROTOCOL *SimpleInput;
469 USB_KB_DEV *UsbKeyboardDevice;
470
471 Status = gBS->OpenProtocol (
472 Controller,
473 &gEfiSimpleTextInProtocolGuid,
474 (VOID **) &SimpleInput,
475 This->DriverBindingHandle,
476 Controller,
477 EFI_OPEN_PROTOCOL_BY_DRIVER
478 );
479 if (EFI_ERROR (Status)) {
480 return EFI_UNSUPPORTED;
481 }
482
483 //
484 // Get USB_KB_DEV instance.
485 //
486 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
487
488 gBS->CloseProtocol (
489 Controller,
490 &gEfiSimpleTextInProtocolGuid,
491 This->DriverBindingHandle,
492 Controller
493 );
494
495 //
496 // Uninstall the Asyn Interrupt Transfer from this device
497 // will disable the key data input from this device
498 //
499 KbdReportStatusCode (
500 UsbKeyboardDevice->DevicePath,
501 EFI_PROGRESS_CODE,
502 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE)
503 );
504
505 //
506 // Destroy asynchronous interrupt transfer
507 //
508 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
509 UsbKeyboardDevice->UsbIo,
510 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
511 FALSE,
512 UsbKeyboardDevice->IntEndpointDescriptor.Interval,
513 0,
514 NULL,
515 NULL
516 );
517
518 gBS->CloseProtocol (
519 Controller,
520 &gEfiUsbIoProtocolGuid,
521 This->DriverBindingHandle,
522 Controller
523 );
524
525 Status = gBS->UninstallMultipleProtocolInterfaces (
526 Controller,
527 &gEfiSimpleTextInProtocolGuid,
528 &UsbKeyboardDevice->SimpleInput,
529 &gEfiHotPlugDeviceGuid,
530 NULL,
531 NULL
532 );
533 //
534 // free all the resources.
535 //
536 gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
537 gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
538 gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey);
539
540 if (UsbKeyboardDevice->ControllerNameTable != NULL) {
541 FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
542 }
543
544 gBS->FreePool (UsbKeyboardDevice);
545
546 return Status;
547
548 }
549
550
551 EFI_STATUS
552 EFIAPI
553 USBKeyboardReset (
554 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,
555 IN BOOLEAN ExtendedVerification
556 )
557 /*++
558
559 Routine Description:
560 Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.Reset() function.
561
562 Arguments:
563 This The EFI_SIMPLE_TEXT_IN_PROTOCOL instance.
564 ExtendedVerification
565 Indicates that the driver may perform a more exhaustive
566 verification operation of the device during reset.
567
568 Returns:
569 EFI_SUCCESS - Success
570 EFI_DEVICE_ERROR - Hardware Error
571 --*/
572 {
573 EFI_STATUS Status;
574 USB_KB_DEV *UsbKeyboardDevice;
575
576 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
577
578 KbdReportStatusCode (
579 UsbKeyboardDevice->DevicePath,
580 EFI_PROGRESS_CODE,
581 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET)
582 );
583
584 //
585 // Non Exhaustive reset:
586 // only reset private data structures.
587 //
588 if (!ExtendedVerification) {
589 //
590 // Clear the key buffer of this Usb keyboard
591 //
592 KbdReportStatusCode (
593 UsbKeyboardDevice->DevicePath,
594 EFI_PROGRESS_CODE,
595 (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER)
596 );
597
598 InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));
599 UsbKeyboardDevice->CurKeyChar = 0;
600 return EFI_SUCCESS;
601 }
602
603 //
604 // Exhaustive reset
605 //
606 Status = InitUSBKeyboard (UsbKeyboardDevice);
607 UsbKeyboardDevice->CurKeyChar = 0;
608 if (EFI_ERROR (Status)) {
609 return EFI_DEVICE_ERROR;
610 }
611
612 return EFI_SUCCESS;
613 }
614
615 STATIC
616 EFI_STATUS
617 EFIAPI
618 USBKeyboardReadKeyStroke (
619 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,
620 OUT EFI_INPUT_KEY *Key
621 )
622 /*++
623
624 Routine Description:
625 Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.ReadKeyStroke() function.
626
627 Arguments:
628 This The EFI_SIMPLE_TEXT_IN_PROTOCOL instance.
629 Key A pointer to a buffer that is filled in with the keystroke
630 information for the key that was pressed.
631
632 Returns:
633 EFI_SUCCESS - Success
634 --*/
635 {
636 USB_KB_DEV *UsbKeyboardDevice;
637 EFI_STATUS Status;
638 UINT8 KeyChar;
639
640 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
641
642 //
643 // if there is no saved ASCII byte, fetch it
644 // by calling USBKeyboardCheckForKey().
645 //
646 if (UsbKeyboardDevice->CurKeyChar == 0) {
647 Status = USBKeyboardCheckForKey (UsbKeyboardDevice);
648 if (EFI_ERROR (Status)) {
649 return Status;
650 }
651 }
652
653 Key->UnicodeChar = 0;
654 Key->ScanCode = SCAN_NULL;
655
656 KeyChar = UsbKeyboardDevice->CurKeyChar;
657
658 UsbKeyboardDevice->CurKeyChar = 0;
659
660 //
661 // Translate saved ASCII byte into EFI_INPUT_KEY
662 //
663 Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, Key);
664
665 return Status;
666
667 }
668
669 STATIC
670 VOID
671 EFIAPI
672 USBKeyboardWaitForKey (
673 IN EFI_EVENT Event,
674 IN VOID *Context
675 )
676 /*++
677
678 Routine Description:
679 Handler function for WaitForKey event.
680
681 Arguments:
682 Event Event to be signaled when a key is pressed.
683 Context Points to USB_KB_DEV instance.
684
685 Returns:
686 VOID
687 --*/
688 {
689 USB_KB_DEV *UsbKeyboardDevice;
690
691 UsbKeyboardDevice = (USB_KB_DEV *) Context;
692
693 if (UsbKeyboardDevice->CurKeyChar == 0) {
694
695 if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) {
696 return ;
697 }
698 }
699 //
700 // If has key pending, signal the event.
701 //
702 gBS->SignalEvent (Event);
703 }
704
705
706 STATIC
707 EFI_STATUS
708 USBKeyboardCheckForKey (
709 IN USB_KB_DEV *UsbKeyboardDevice
710 )
711 /*++
712
713 Routine Description:
714 Check whether there is key pending.
715
716 Arguments:
717 UsbKeyboardDevice The USB_KB_DEV instance.
718
719 Returns:
720 EFI_SUCCESS - Success
721 --*/
722 {
723 EFI_STATUS Status;
724 UINT8 KeyChar;
725
726 //
727 // Fetch raw data from the USB keyboard input,
728 // and translate it into ASCII data.
729 //
730 Status = USBParseKey (UsbKeyboardDevice, &KeyChar);
731 if (EFI_ERROR (Status)) {
732 return Status;
733 }
734
735 UsbKeyboardDevice->CurKeyChar = KeyChar;
736 return EFI_SUCCESS;
737 }
738
739 VOID
740 KbdReportStatusCode (
741 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
742 IN EFI_STATUS_CODE_TYPE CodeType,
743 IN EFI_STATUS_CODE_VALUE Value
744 )
745 /*++
746
747 Routine Description:
748 Report Status Code in Usb Bot Driver
749
750 Arguments:
751 DevicePath - Use this to get Device Path
752 CodeType - Status Code Type
753 CodeValue - Status Code Value
754
755 Returns:
756 None
757
758 --*/
759 {
760
761 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
762 CodeType,
763 Value,
764 DevicePath
765 );
766 }