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