1 /** @file
2   USB Mouse Driver that manages USB mouse and produces Simple Pointer Protocol.
3 
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "UsbMouse.h"
10 
11 EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding = {
12   USBMouseDriverBindingSupported,
13   USBMouseDriverBindingStart,
14   USBMouseDriverBindingStop,
15   0xa,
16   NULL,
17   NULL
18 };
19 
20 /**
21   Entrypoint of USB Mouse Driver.
22 
23   This function is the entrypoint of USB Mouse Driver. It installs Driver Binding
24   Protocols together with Component Name Protocols.
25 
26   @param  ImageHandle       The firmware allocated handle for the EFI image.
27   @param  SystemTable       A pointer to the EFI System Table.
28 
29   @retval EFI_SUCCESS       The entry point is executed successfully.
30 
31 **/
32 EFI_STATUS
33 EFIAPI
USBMouseDriverBindingEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)34 USBMouseDriverBindingEntryPoint (
35   IN EFI_HANDLE           ImageHandle,
36   IN EFI_SYSTEM_TABLE     *SystemTable
37   )
38 {
39   EFI_STATUS              Status;
40 
41   Status = EfiLibInstallDriverBindingComponentName2 (
42              ImageHandle,
43              SystemTable,
44              &gUsbMouseDriverBinding,
45              ImageHandle,
46              &gUsbMouseComponentName,
47              &gUsbMouseComponentName2
48              );
49   ASSERT_EFI_ERROR (Status);
50 
51   return EFI_SUCCESS;
52 }
53 
54 
55 /**
56   Check whether USB mouse driver supports this device.
57 
58   @param  This                   The USB mouse driver binding protocol.
59   @param  Controller             The controller handle to check.
60   @param  RemainingDevicePath    The remaining device path.
61 
62   @retval EFI_SUCCESS            The driver supports this controller.
63   @retval other                  This device isn't supported.
64 
65 **/
66 EFI_STATUS
67 EFIAPI
USBMouseDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)68 USBMouseDriverBindingSupported (
69   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
70   IN EFI_HANDLE                     Controller,
71   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
72   )
73 {
74   EFI_STATUS          Status;
75   EFI_USB_IO_PROTOCOL *UsbIo;
76 
77   Status = gBS->OpenProtocol (
78                   Controller,
79                   &gEfiUsbIoProtocolGuid,
80                   (VOID **) &UsbIo,
81                   This->DriverBindingHandle,
82                   Controller,
83                   EFI_OPEN_PROTOCOL_BY_DRIVER
84                   );
85   if (EFI_ERROR (Status)) {
86     return Status;
87   }
88 
89   //
90   // Use the USB I/O Protocol interface to check whether Controller is
91   // a mouse device that can be managed by this driver.
92   //
93   Status = EFI_SUCCESS;
94   if (!IsUsbMouse (UsbIo)) {
95     Status = EFI_UNSUPPORTED;
96   }
97 
98   gBS->CloseProtocol (
99         Controller,
100         &gEfiUsbIoProtocolGuid,
101         This->DriverBindingHandle,
102         Controller
103         );
104 
105   return Status;
106 }
107 
108 
109 /**
110   Starts the mouse device with this driver.
111 
112   This function consumes USB I/O Protocol, initializes USB mouse device,
113   installs Simple Pointer Protocol, and submits Asynchronous Interrupt
114   Transfer to manage the USB mouse device.
115 
116   @param  This                  The USB mouse driver binding instance.
117   @param  Controller            Handle of device to bind driver to.
118   @param  RemainingDevicePath   Optional parameter use to pick a specific child
119                                 device to start.
120 
121   @retval EFI_SUCCESS           This driver supports this device.
122   @retval EFI_UNSUPPORTED       This driver does not support this device.
123   @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
124   @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
125   @retval EFI_ALREADY_STARTED   This driver has been started.
126 
127 **/
128 EFI_STATUS
129 EFIAPI
USBMouseDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)130 USBMouseDriverBindingStart (
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_USB_IO_PROTOCOL         *UsbIo;
138   USB_MOUSE_DEV               *UsbMouseDevice;
139   UINT8                       EndpointNumber;
140   EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
141   UINT8                       Index;
142   UINT8                       EndpointAddr;
143   UINT8                       PollingInterval;
144   UINT8                       PacketSize;
145   BOOLEAN                     Found;
146   EFI_TPL                     OldTpl;
147 
148   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
149   //
150   // Open USB I/O Protocol
151   //
152   Status = gBS->OpenProtocol (
153                   Controller,
154                   &gEfiUsbIoProtocolGuid,
155                   (VOID **) &UsbIo,
156                   This->DriverBindingHandle,
157                   Controller,
158                   EFI_OPEN_PROTOCOL_BY_DRIVER
159                   );
160   if (EFI_ERROR (Status)) {
161     goto ErrorExit1;
162   }
163 
164   UsbMouseDevice = AllocateZeroPool (sizeof (USB_MOUSE_DEV));
165   ASSERT (UsbMouseDevice != NULL);
166 
167   UsbMouseDevice->UsbIo     = UsbIo;
168   UsbMouseDevice->Signature = USB_MOUSE_DEV_SIGNATURE;
169 
170   //
171   // Get the Device Path Protocol on Controller's handle
172   //
173   Status = gBS->OpenProtocol (
174                   Controller,
175                   &gEfiDevicePathProtocolGuid,
176                   (VOID **) &UsbMouseDevice->DevicePath,
177                   This->DriverBindingHandle,
178                   Controller,
179                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
180                   );
181 
182   if (EFI_ERROR (Status)) {
183     goto ErrorExit;
184   }
185 
186   //
187   // Report Status Code here since USB mouse will be detected next.
188   //
189   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
190     EFI_PROGRESS_CODE,
191     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT),
192     UsbMouseDevice->DevicePath
193     );
194 
195   //
196   // Get interface & endpoint descriptor
197   //
198   UsbIo->UsbGetInterfaceDescriptor (
199            UsbIo,
200            &UsbMouseDevice->InterfaceDescriptor
201            );
202 
203   EndpointNumber = UsbMouseDevice->InterfaceDescriptor.NumEndpoints;
204 
205   //
206   // Traverse endpoints to find interrupt endpoint IN
207   //
208   Found = FALSE;
209   for (Index = 0; Index < EndpointNumber; Index++) {
210     UsbIo->UsbGetEndpointDescriptor (
211              UsbIo,
212              Index,
213              &EndpointDescriptor
214              );
215 
216     if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&
217         ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {
218       //
219       // We only care interrupt endpoint here
220       //
221       CopyMem(&UsbMouseDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
222       Found = TRUE;
223       break;
224     }
225   }
226 
227   if (!Found) {
228     //
229     // Report Status Code to indicate that there is no USB mouse
230     //
231     REPORT_STATUS_CODE (
232       EFI_ERROR_CODE | EFI_ERROR_MINOR,
233       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED)
234       );
235     //
236     // No interrupt endpoint found, then return unsupported.
237     //
238     Status = EFI_UNSUPPORTED;
239     goto ErrorExit;
240   }
241 
242   //
243   // Report Status Code here since USB mouse has be detected.
244   //
245   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
246     EFI_PROGRESS_CODE,
247     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED),
248     UsbMouseDevice->DevicePath
249     );
250 
251   Status = InitializeUsbMouseDevice (UsbMouseDevice);
252   if (EFI_ERROR (Status)) {
253     //
254     // Fail to initialize USB mouse device.
255     //
256     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
257       EFI_ERROR_CODE | EFI_ERROR_MINOR,
258       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR),
259       UsbMouseDevice->DevicePath
260       );
261 
262     goto ErrorExit;
263   }
264 
265   //
266   // Initialize and install EFI Simple Pointer Protocol.
267   //
268   UsbMouseDevice->SimplePointerProtocol.GetState  = GetMouseState;
269   UsbMouseDevice->SimplePointerProtocol.Reset     = UsbMouseReset;
270   UsbMouseDevice->SimplePointerProtocol.Mode      = &UsbMouseDevice->Mode;
271 
272   Status = gBS->CreateEvent (
273                   EVT_NOTIFY_WAIT,
274                   TPL_NOTIFY,
275                   UsbMouseWaitForInput,
276                   UsbMouseDevice,
277                   &((UsbMouseDevice->SimplePointerProtocol).WaitForInput)
278                   );
279   if (EFI_ERROR (Status)) {
280     goto ErrorExit;
281   }
282 
283   Status = gBS->InstallProtocolInterface (
284                   &Controller,
285                   &gEfiSimplePointerProtocolGuid,
286                   EFI_NATIVE_INTERFACE,
287                   &UsbMouseDevice->SimplePointerProtocol
288                   );
289 
290   if (EFI_ERROR (Status)) {
291     goto ErrorExit;
292   }
293 
294   //
295   // The next step would be submitting Asynchronous Interrupt Transfer on this mouse device.
296   // After that we will be able to get key data from it. Thus this is deemed as
297   // the enable action of the mouse, so report status code accordingly.
298   //
299   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
300     EFI_PROGRESS_CODE,
301     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE),
302     UsbMouseDevice->DevicePath
303     );
304 
305   //
306   // Submit Asynchronous Interrupt Transfer to manage this device.
307   //
308   EndpointAddr    = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress;
309   PollingInterval = UsbMouseDevice->IntEndpointDescriptor.Interval;
310   PacketSize      = (UINT8) (UsbMouseDevice->IntEndpointDescriptor.MaxPacketSize);
311 
312   Status = UsbIo->UsbAsyncInterruptTransfer (
313                     UsbIo,
314                     EndpointAddr,
315                     TRUE,
316                     PollingInterval,
317                     PacketSize,
318                     OnMouseInterruptComplete,
319                     UsbMouseDevice
320                     );
321 
322   if (EFI_ERROR (Status)) {
323     //
324     // If submit error, uninstall that interface
325     //
326     gBS->UninstallProtocolInterface (
327            Controller,
328            &gEfiSimplePointerProtocolGuid,
329            &UsbMouseDevice->SimplePointerProtocol
330            );
331     goto ErrorExit;
332   }
333 
334   UsbMouseDevice->ControllerNameTable = NULL;
335   AddUnicodeString2 (
336     "eng",
337     gUsbMouseComponentName.SupportedLanguages,
338     &UsbMouseDevice->ControllerNameTable,
339     L"Generic Usb Mouse",
340     TRUE
341     );
342   AddUnicodeString2 (
343     "en",
344     gUsbMouseComponentName2.SupportedLanguages,
345     &UsbMouseDevice->ControllerNameTable,
346     L"Generic Usb Mouse",
347     FALSE
348     );
349 
350   gBS->RestoreTPL (OldTpl);
351 
352   return EFI_SUCCESS;
353 
354 //
355 // Error handler
356 //
357 ErrorExit:
358   if (EFI_ERROR (Status)) {
359     gBS->CloseProtocol (
360           Controller,
361           &gEfiUsbIoProtocolGuid,
362           This->DriverBindingHandle,
363           Controller
364           );
365 
366     if (UsbMouseDevice != NULL) {
367       if ((UsbMouseDevice->SimplePointerProtocol).WaitForInput != NULL) {
368         gBS->CloseEvent ((UsbMouseDevice->SimplePointerProtocol).WaitForInput);
369       }
370 
371       FreePool (UsbMouseDevice);
372       UsbMouseDevice = NULL;
373     }
374   }
375 
376 ErrorExit1:
377   gBS->RestoreTPL (OldTpl);
378   return Status;
379 }
380 
381 
382 /**
383   Stop the USB mouse device handled by this driver.
384 
385   @param  This                   The USB mouse driver binding protocol.
386   @param  Controller             The controller to release.
387   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
388   @param  ChildHandleBuffer      The array of child handle.
389 
390   @retval EFI_SUCCESS            The device was stopped.
391   @retval EFI_UNSUPPORTED        Simple Pointer Protocol is not installed on Controller.
392   @retval Others                 Fail to uninstall protocols attached on the device.
393 
394 **/
395 EFI_STATUS
396 EFIAPI
USBMouseDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)397 USBMouseDriverBindingStop (
398   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
399   IN  EFI_HANDLE                    Controller,
400   IN  UINTN                         NumberOfChildren,
401   IN  EFI_HANDLE                    *ChildHandleBuffer
402   )
403 {
404   EFI_STATUS                  Status;
405   USB_MOUSE_DEV               *UsbMouseDevice;
406   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
407   EFI_USB_IO_PROTOCOL         *UsbIo;
408 
409   Status = gBS->OpenProtocol (
410                   Controller,
411                   &gEfiSimplePointerProtocolGuid,
412                   (VOID **) &SimplePointerProtocol,
413                   This->DriverBindingHandle,
414                   Controller,
415                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
416                   );
417 
418   if (EFI_ERROR (Status)) {
419     return EFI_UNSUPPORTED;
420   }
421 
422   UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol);
423 
424   UsbIo = UsbMouseDevice->UsbIo;
425 
426   //
427   // The key data input from this device will be disabled.
428   //
429   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
430     EFI_PROGRESS_CODE,
431     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE),
432     UsbMouseDevice->DevicePath
433     );
434 
435   //
436   // Delete the Asynchronous Interrupt Transfer from this device
437   //
438   UsbIo->UsbAsyncInterruptTransfer (
439            UsbIo,
440            UsbMouseDevice->IntEndpointDescriptor.EndpointAddress,
441            FALSE,
442            UsbMouseDevice->IntEndpointDescriptor.Interval,
443            0,
444            NULL,
445            NULL
446            );
447 
448   Status = gBS->UninstallProtocolInterface (
449                   Controller,
450                   &gEfiSimplePointerProtocolGuid,
451                   &UsbMouseDevice->SimplePointerProtocol
452                   );
453   if (EFI_ERROR (Status)) {
454     return Status;
455   }
456 
457   gBS->CloseProtocol (
458          Controller,
459          &gEfiUsbIoProtocolGuid,
460          This->DriverBindingHandle,
461          Controller
462          );
463 
464   //
465   // Free all resources.
466   //
467   gBS->CloseEvent (UsbMouseDevice->SimplePointerProtocol.WaitForInput);
468 
469   if (UsbMouseDevice->DelayedRecoveryEvent != NULL) {
470     gBS->CloseEvent (UsbMouseDevice->DelayedRecoveryEvent);
471     UsbMouseDevice->DelayedRecoveryEvent = NULL;
472   }
473 
474   if (UsbMouseDevice->ControllerNameTable != NULL) {
475     FreeUnicodeStringTable (UsbMouseDevice->ControllerNameTable);
476   }
477 
478   FreePool (UsbMouseDevice);
479 
480   return EFI_SUCCESS;
481 
482 }
483 
484 
485 /**
486   Uses USB I/O to check whether the device is a USB mouse device.
487 
488   @param  UsbIo    Pointer to a USB I/O protocol instance.
489 
490   @retval TRUE     Device is a USB mouse device.
491   @retval FALSE    Device is a not USB mouse device.
492 
493 **/
494 BOOLEAN
IsUsbMouse(IN EFI_USB_IO_PROTOCOL * UsbIo)495 IsUsbMouse (
496   IN  EFI_USB_IO_PROTOCOL     *UsbIo
497   )
498 {
499   EFI_STATUS                    Status;
500   EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
501 
502   //
503   // Get the default interface descriptor
504   //
505   Status = UsbIo->UsbGetInterfaceDescriptor (
506                     UsbIo,
507                     &InterfaceDescriptor
508                     );
509 
510   if (EFI_ERROR (Status)) {
511     return FALSE;
512   }
513 
514   if ((InterfaceDescriptor.InterfaceClass == CLASS_HID) &&
515       (InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT) &&
516       (InterfaceDescriptor.InterfaceProtocol == PROTOCOL_MOUSE)
517       ) {
518     return TRUE;
519   }
520 
521   return FALSE;
522 }
523 
524 
525 /**
526   Initialize the USB mouse device.
527 
528   This function retrieves and parses HID report descriptor, and
529   initializes state of USB_MOUSE_DEV. Then it sets indefinite idle
530   rate for the device. Finally it creates event for delayed recovery,
531   which deals with device error.
532 
533   @param  UsbMouseDev           Device instance to be initialized.
534 
535   @retval EFI_SUCCESS           USB mouse device successfully initialized..
536   @retval EFI_UNSUPPORTED       HID descriptor type is not report descriptor.
537   @retval Other                 USB mouse device was not initialized successfully.
538 
539 **/
540 EFI_STATUS
InitializeUsbMouseDevice(IN OUT USB_MOUSE_DEV * UsbMouseDev)541 InitializeUsbMouseDevice (
542   IN OUT USB_MOUSE_DEV           *UsbMouseDev
543   )
544 {
545   EFI_USB_IO_PROTOCOL       *UsbIo;
546   UINT8                     Protocol;
547   EFI_STATUS                Status;
548   EFI_USB_HID_DESCRIPTOR    *MouseHidDesc;
549   UINT8                     *ReportDesc;
550   EFI_USB_CONFIG_DESCRIPTOR ConfigDesc;
551   VOID                      *Buf;
552   UINT32                    TransferResult;
553   UINT16                    Total;
554   USB_DESC_HEAD             *Head;
555   BOOLEAN                   Start;
556 
557   UsbIo = UsbMouseDev->UsbIo;
558 
559   //
560   // Get the current configuration descriptor. Note that it doesn't include other descriptors.
561   //
562   Status = UsbIo->UsbGetConfigDescriptor (
563                     UsbIo,
564                     &ConfigDesc
565                     );
566   if (EFI_ERROR (Status)) {
567     return Status;
568   }
569 
570   //
571   // By issuing Get_Descriptor(Configuration) request with total length, we get the Configuration descriptor,
572   // all Interface descriptors, all Endpoint descriptors, and the HID descriptor for each interface.
573   //
574   Buf = AllocateZeroPool (ConfigDesc.TotalLength);
575   if (Buf == NULL) {
576     return EFI_OUT_OF_RESOURCES;
577   }
578 
579   Status = UsbGetDescriptor (
580              UsbIo,
581              (UINT16)((USB_DESC_TYPE_CONFIG << 8) | (ConfigDesc.ConfigurationValue - 1)),
582              0,
583              ConfigDesc.TotalLength,
584              Buf,
585              &TransferResult
586              );
587   if (EFI_ERROR (Status)) {
588     FreePool (Buf);
589     return Status;
590   }
591 
592   Total = 0;
593   Start = FALSE;
594   Head  = (USB_DESC_HEAD *)Buf;
595   MouseHidDesc = NULL;
596 
597   //
598   // Get HID descriptor from the receipt of Get_Descriptor(Configuration) request.
599   // This algorithm is based on the fact that the HID descriptor shall be interleaved
600   // between the interface and endpoint descriptors for HID interfaces.
601   //
602   while (Total < ConfigDesc.TotalLength) {
603     if (Head->Type == USB_DESC_TYPE_INTERFACE) {
604       if ((((USB_INTERFACE_DESCRIPTOR *)Head)->InterfaceNumber == UsbMouseDev->InterfaceDescriptor.InterfaceNumber) &&
605         (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseDev->InterfaceDescriptor.AlternateSetting)) {
606         Start = TRUE;
607       }
608     }
609     if (Start && (Head->Type == USB_DESC_TYPE_ENDPOINT)) {
610       break;
611     }
612     if (Start && (Head->Type == USB_DESC_TYPE_HID)) {
613       MouseHidDesc = (EFI_USB_HID_DESCRIPTOR *)Head;
614       break;
615     }
616     Total = Total + (UINT16)Head->Len;
617     Head  = (USB_DESC_HEAD*)((UINT8 *)Buf + Total);
618   }
619 
620   if (MouseHidDesc == NULL) {
621     FreePool (Buf);
622     return EFI_UNSUPPORTED;
623   }
624 
625   //
626   // Get report descriptor
627   //
628   if (MouseHidDesc->HidClassDesc[0].DescriptorType != USB_DESC_TYPE_REPORT) {
629     FreePool (Buf);
630     return EFI_UNSUPPORTED;
631   }
632 
633   ReportDesc = AllocateZeroPool (MouseHidDesc->HidClassDesc[0].DescriptorLength);
634   ASSERT (ReportDesc != NULL);
635 
636   Status = UsbGetReportDescriptor (
637              UsbIo,
638              UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
639              MouseHidDesc->HidClassDesc[0].DescriptorLength,
640              ReportDesc
641              );
642 
643   if (EFI_ERROR (Status)) {
644     FreePool (Buf);
645     FreePool (ReportDesc);
646     return Status;
647   }
648 
649   //
650   // Parse report descriptor
651   //
652   Status = ParseMouseReportDescriptor (
653              UsbMouseDev,
654              ReportDesc,
655              MouseHidDesc->HidClassDesc[0].DescriptorLength
656              );
657 
658   if (EFI_ERROR (Status)) {
659     FreePool (Buf);
660     FreePool (ReportDesc);
661     return Status;
662   }
663 
664   //
665   // Check the presence of left and right buttons,
666   // and initialize fields of EFI_SIMPLE_POINTER_MODE.
667   //
668   if (UsbMouseDev->NumberOfButtons >= 1) {
669     UsbMouseDev->Mode.LeftButton = TRUE;
670   }
671   if (UsbMouseDev->NumberOfButtons > 1) {
672     UsbMouseDev->Mode.RightButton = TRUE;
673   }
674   UsbMouseDev->Mode.ResolutionX = 8;
675   UsbMouseDev->Mode.ResolutionY = 8;
676   UsbMouseDev->Mode.ResolutionZ = 0;
677 
678   //
679   // Set boot protocol for the USB mouse.
680   // This driver only supports boot protocol.
681   //
682   UsbGetProtocolRequest (
683     UsbIo,
684     UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
685     &Protocol
686     );
687   if (Protocol != BOOT_PROTOCOL) {
688     Status = UsbSetProtocolRequest (
689                UsbIo,
690                UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
691                BOOT_PROTOCOL
692                );
693 
694     if (EFI_ERROR (Status)) {
695       FreePool (Buf);
696       FreePool (ReportDesc);
697       return Status;
698     }
699   }
700 
701   FreePool (Buf);
702   FreePool (ReportDesc);
703 
704   //
705   // Create event for delayed recovery, which deals with device error.
706   //
707   if (UsbMouseDev->DelayedRecoveryEvent != NULL) {
708     gBS->CloseEvent (UsbMouseDev->DelayedRecoveryEvent);
709     UsbMouseDev->DelayedRecoveryEvent = 0;
710   }
711 
712   gBS->CreateEvent (
713          EVT_TIMER | EVT_NOTIFY_SIGNAL,
714          TPL_NOTIFY,
715          USBMouseRecoveryHandler,
716          UsbMouseDev,
717          &UsbMouseDev->DelayedRecoveryEvent
718          );
719 
720   return EFI_SUCCESS;
721 }
722 
723 
724 /**
725   Handler function for USB mouse's asynchronous interrupt transfer.
726 
727   This function is the handler function for USB mouse's asynchronous interrupt transfer
728   to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
729   get button and movement state.
730 
731   @param  Data             A pointer to a buffer that is filled with key data which is
732                            retrieved via asynchronous interrupt transfer.
733   @param  DataLength       Indicates the size of the data buffer.
734   @param  Context          Pointing to USB_KB_DEV instance.
735   @param  Result           Indicates the result of the asynchronous interrupt transfer.
736 
737   @retval EFI_SUCCESS      Asynchronous interrupt transfer is handled successfully.
738   @retval EFI_DEVICE_ERROR Hardware error occurs.
739 
740 **/
741 EFI_STATUS
742 EFIAPI
OnMouseInterruptComplete(IN VOID * Data,IN UINTN DataLength,IN VOID * Context,IN UINT32 Result)743 OnMouseInterruptComplete (
744   IN  VOID        *Data,
745   IN  UINTN       DataLength,
746   IN  VOID        *Context,
747   IN  UINT32      Result
748   )
749 {
750   USB_MOUSE_DEV       *UsbMouseDevice;
751   EFI_USB_IO_PROTOCOL *UsbIo;
752   UINT8               EndpointAddr;
753   UINT32              UsbResult;
754 
755   UsbMouseDevice  = (USB_MOUSE_DEV *) Context;
756   UsbIo           = UsbMouseDevice->UsbIo;
757 
758   if (Result != EFI_USB_NOERROR) {
759     //
760     // Some errors happen during the process
761     //
762     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
763       EFI_ERROR_CODE | EFI_ERROR_MINOR,
764       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
765       UsbMouseDevice->DevicePath
766       );
767 
768     if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
769       EndpointAddr = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress;
770 
771       UsbClearEndpointHalt (
772         UsbIo,
773         EndpointAddr,
774         &UsbResult
775         );
776     }
777 
778     //
779     // Delete & Submit this interrupt again
780     // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
781     //
782     UsbIo->UsbAsyncInterruptTransfer (
783              UsbIo,
784              UsbMouseDevice->IntEndpointDescriptor.EndpointAddress,
785              FALSE,
786              0,
787              0,
788              NULL,
789              NULL
790              );
791     //
792     // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
793     //
794     gBS->SetTimer (
795            UsbMouseDevice->DelayedRecoveryEvent,
796            TimerRelative,
797            EFI_USB_INTERRUPT_DELAY
798            );
799     return EFI_DEVICE_ERROR;
800   }
801 
802   //
803   // If no error and no data, just return EFI_SUCCESS.
804   //
805   if (DataLength == 0 || Data == NULL) {
806     return EFI_SUCCESS;
807   }
808 
809   //
810   // Check mouse Data
811   // USB HID Specification specifies following data format:
812   // Byte    Bits    Description
813   // 0       0       Button 1
814   //         1       Button 2
815   //         2       Button 3
816   //         4 to 7  Device-specific
817   // 1       0 to 7  X displacement
818   // 2       0 to 7  Y displacement
819   // 3 to n  0 to 7  Device specific (optional)
820   //
821   if (DataLength < 3) {
822     return EFI_DEVICE_ERROR;
823   }
824 
825   UsbMouseDevice->StateChanged = TRUE;
826 
827   UsbMouseDevice->State.LeftButton  = (BOOLEAN) ((*(UINT8 *) Data & BIT0) != 0);
828   UsbMouseDevice->State.RightButton = (BOOLEAN) ((*(UINT8 *) Data & BIT1) != 0);
829   UsbMouseDevice->State.RelativeMovementX += *((INT8 *) Data + 1);
830   UsbMouseDevice->State.RelativeMovementY += *((INT8 *) Data + 2);
831 
832   if (DataLength > 3) {
833     UsbMouseDevice->State.RelativeMovementZ += *((INT8 *) Data + 3);
834   }
835 
836   return EFI_SUCCESS;
837 }
838 
839 /**
840   Retrieves the current state of a pointer device.
841 
842   @param  This                  A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
843   @param  MouseState            A pointer to the state information on the pointer device.
844 
845   @retval EFI_SUCCESS           The state of the pointer device was returned in State.
846   @retval EFI_NOT_READY         The state of the pointer device has not changed since the last call to
847                                 GetState().
848   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to retrieve the pointer device's
849                                 current state.
850   @retval EFI_INVALID_PARAMETER MouseState is NULL.
851 
852 **/
853 EFI_STATUS
854 EFIAPI
GetMouseState(IN EFI_SIMPLE_POINTER_PROTOCOL * This,OUT EFI_SIMPLE_POINTER_STATE * MouseState)855 GetMouseState (
856   IN   EFI_SIMPLE_POINTER_PROTOCOL  *This,
857   OUT  EFI_SIMPLE_POINTER_STATE     *MouseState
858   )
859 {
860   USB_MOUSE_DEV *MouseDev;
861 
862   if (MouseState == NULL) {
863     return EFI_INVALID_PARAMETER;
864   }
865 
866   MouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This);
867 
868   if (!MouseDev->StateChanged) {
869     return EFI_NOT_READY;
870   }
871 
872   //
873   // Retrieve mouse state from USB_MOUSE_DEV, which was filled by OnMouseInterruptComplete()
874   //
875   CopyMem (
876     MouseState,
877     &MouseDev->State,
878     sizeof (EFI_SIMPLE_POINTER_STATE)
879     );
880 
881   //
882   // Clear previous move state
883   //
884   MouseDev->State.RelativeMovementX = 0;
885   MouseDev->State.RelativeMovementY = 0;
886   MouseDev->State.RelativeMovementZ = 0;
887 
888   MouseDev->StateChanged            = FALSE;
889 
890   return EFI_SUCCESS;
891 }
892 
893 
894 /**
895   Resets the pointer device hardware.
896 
897   @param  This                  A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
898   @param  ExtendedVerification  Indicates that the driver may perform a more exhaustive
899                                 verification operation of the device during reset.
900 
901   @retval EFI_SUCCESS           The device was reset.
902   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could not be reset.
903 
904 **/
905 EFI_STATUS
906 EFIAPI
UsbMouseReset(IN EFI_SIMPLE_POINTER_PROTOCOL * This,IN BOOLEAN ExtendedVerification)907 UsbMouseReset (
908   IN EFI_SIMPLE_POINTER_PROTOCOL    *This,
909   IN BOOLEAN                        ExtendedVerification
910   )
911 {
912   USB_MOUSE_DEV       *UsbMouseDevice;
913 
914   UsbMouseDevice  = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This);
915 
916   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
917     EFI_PROGRESS_CODE,
918     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
919     UsbMouseDevice->DevicePath
920     );
921 
922   //
923   // Clear mouse state.
924   //
925   ZeroMem (
926     &UsbMouseDevice->State,
927     sizeof (EFI_SIMPLE_POINTER_STATE)
928     );
929   UsbMouseDevice->StateChanged = FALSE;
930 
931   return EFI_SUCCESS;
932 }
933 
934 /**
935   Event notification function for EFI_SIMPLE_POINTER_PROTOCOL.WaitForInput event.
936 
937   @param  Event        Event to be signaled when there's input from mouse.
938   @param  Context      Points to USB_MOUSE_DEV instance.
939 
940 **/
941 VOID
942 EFIAPI
UsbMouseWaitForInput(IN EFI_EVENT Event,IN VOID * Context)943 UsbMouseWaitForInput (
944   IN  EFI_EVENT               Event,
945   IN  VOID                    *Context
946   )
947 {
948   USB_MOUSE_DEV *UsbMouseDev;
949 
950   UsbMouseDev = (USB_MOUSE_DEV *) Context;
951 
952   //
953   // If there's input from mouse, signal the event.
954   //
955   if (UsbMouseDev->StateChanged) {
956     gBS->SignalEvent (Event);
957   }
958 }
959 
960 /**
961   Handler for Delayed Recovery event.
962 
963   This function is the handler for Delayed Recovery event triggered
964   by timer.
965   After a device error occurs, the event would be triggered
966   with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
967   is defined in USB standard for error handling.
968 
969   @param  Event              The Delayed Recovery event.
970   @param  Context            Points to the USB_MOUSE_DEV instance.
971 
972 **/
973 VOID
974 EFIAPI
USBMouseRecoveryHandler(IN EFI_EVENT Event,IN VOID * Context)975 USBMouseRecoveryHandler (
976   IN    EFI_EVENT    Event,
977   IN    VOID         *Context
978   )
979 {
980   USB_MOUSE_DEV       *UsbMouseDev;
981   EFI_USB_IO_PROTOCOL *UsbIo;
982 
983   UsbMouseDev = (USB_MOUSE_DEV *) Context;
984 
985   UsbIo       = UsbMouseDev->UsbIo;
986 
987   //
988   // Re-submit Asynchronous Interrupt Transfer for recovery.
989   //
990   UsbIo->UsbAsyncInterruptTransfer (
991            UsbIo,
992            UsbMouseDev->IntEndpointDescriptor.EndpointAddress,
993            TRUE,
994            UsbMouseDev->IntEndpointDescriptor.Interval,
995            UsbMouseDev->IntEndpointDescriptor.MaxPacketSize,
996            OnMouseInterruptComplete,
997            UsbMouseDev
998            );
999 }
1000