1 /** @file
2   USB Mouse Driver that manages USB mouse and produces Absolute 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 "UsbMouseAbsolutePointer.h"
16 
17 EFI_DRIVER_BINDING_PROTOCOL gUsbMouseAbsolutePointerDriverBinding = {
18   USBMouseAbsolutePointerDriverBindingSupported,
19   USBMouseAbsolutePointerDriverBindingStart,
20   USBMouseAbsolutePointerDriverBindingStop,
21   0x1,
22   NULL,
23   NULL
24 };
25 
26 /**
27   Entrypoint of USB Mouse Absolute Pointer 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
USBMouseAbsolutePointerDriverBindingEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)40 USBMouseAbsolutePointerDriverBindingEntryPoint (
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              &gUsbMouseAbsolutePointerDriverBinding,
51              ImageHandle,
52              &gUsbMouseAbsolutePointerComponentName,
53              &gUsbMouseAbsolutePointerComponentName2
54              );
55   ASSERT_EFI_ERROR (Status);
56 
57   return EFI_SUCCESS;
58 }
59 
60 
61 /**
62   Check whether USB Mouse Absolute Pointer Driver supports this device.
63 
64   @param  This                   The 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
USBMouseAbsolutePointerDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)74 USBMouseAbsolutePointerDriverBindingSupported (
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 Absolute Pointer Protocol, and submits Asynchronous Interrupt
120   Transfer to manage the USB mouse device.
121 
122   @param  This                  The 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
USBMouseAbsolutePointerDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)136 USBMouseAbsolutePointerDriverBindingStart (
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_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
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   UsbMouseAbsolutePointerDevice = AllocateZeroPool (sizeof (USB_MOUSE_ABSOLUTE_POINTER_DEV));
171   ASSERT (UsbMouseAbsolutePointerDevice != NULL);
172 
173   UsbMouseAbsolutePointerDevice->UsbIo     = UsbIo;
174   UsbMouseAbsolutePointerDevice->Signature = USB_MOUSE_ABSOLUTE_POINTER_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 **) &UsbMouseAbsolutePointerDevice->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     UsbMouseAbsolutePointerDevice->DevicePath
199     );
200 
201   //
202   // Get interface & endpoint descriptor
203   //
204   UsbIo->UsbGetInterfaceDescriptor (
205            UsbIo,
206            &UsbMouseAbsolutePointerDevice->InterfaceDescriptor
207            );
208 
209   EndpointNumber = UsbMouseAbsolutePointerDevice->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 (&UsbMouseAbsolutePointerDevice->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     UsbMouseAbsolutePointerDevice->DevicePath
254     );
255 
256   Status = InitializeUsbMouseDevice (UsbMouseAbsolutePointerDevice);
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       UsbMouseAbsolutePointerDevice->DevicePath
265       );
266 
267     goto ErrorExit;
268   }
269 
270   //
271   // Initialize and install EFI Absolute Pointer Protocol.
272   //
273   UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.GetState = GetMouseAbsolutePointerState;
274   UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Reset	  = UsbMouseAbsolutePointerReset;
275   UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Mode	  = &UsbMouseAbsolutePointerDevice->Mode;
276 
277   Status = gBS->CreateEvent (
278                   EVT_NOTIFY_WAIT,
279                   TPL_NOTIFY,
280                   UsbMouseAbsolutePointerWaitForInput,
281                   UsbMouseAbsolutePointerDevice,
282                   &((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput)
283                   );
284   if (EFI_ERROR (Status)) {
285     goto ErrorExit;
286   }
287 
288   Status = gBS->InstallProtocolInterface (
289                   &Controller,
290                   &gEfiAbsolutePointerProtocolGuid,
291                   EFI_NATIVE_INTERFACE,
292                   &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
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     UsbMouseAbsolutePointerDevice->DevicePath
308     );
309 
310   //
311   // Submit Asynchronous Interrupt Transfer to manage this device.
312   //
313   EndpointAddr    = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
314   PollingInterval = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval;
315   PacketSize      = (UINT8) (UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.MaxPacketSize);
316 
317   Status = UsbIo->UsbAsyncInterruptTransfer (
318                     UsbIo,
319                     EndpointAddr,
320                     TRUE,
321                     PollingInterval,
322                     PacketSize,
323                     OnMouseInterruptComplete,
324                     UsbMouseAbsolutePointerDevice
325                     );
326 
327   if (EFI_ERROR (Status)) {
328     //
329     // If submit error, uninstall that interface
330     //
331     gBS->UninstallProtocolInterface (
332            Controller,
333            &gEfiAbsolutePointerProtocolGuid,
334            &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
335            );
336     goto ErrorExit;
337   }
338 
339   UsbMouseAbsolutePointerDevice->ControllerNameTable = NULL;
340   AddUnicodeString2 (
341     "eng",
342     gUsbMouseAbsolutePointerComponentName.SupportedLanguages,
343     &UsbMouseAbsolutePointerDevice->ControllerNameTable,
344     L"Generic Usb Mouse Absolute Pointer",
345       TRUE
346       );
347   AddUnicodeString2 (
348     "en",
349     gUsbMouseAbsolutePointerComponentName2.SupportedLanguages,
350     &UsbMouseAbsolutePointerDevice->ControllerNameTable,
351     L"Generic Usb Mouse Absolute Pointer",
352     FALSE
353     );
354 
355   gBS->RestoreTPL (OldTpl);
356   return EFI_SUCCESS;
357 
358 //
359 // Error handler
360 //
361 ErrorExit:
362   if (EFI_ERROR (Status)) {
363     gBS->CloseProtocol (
364           Controller,
365           &gEfiUsbIoProtocolGuid,
366           This->DriverBindingHandle,
367           Controller
368           );
369 
370     if (UsbMouseAbsolutePointerDevice != NULL) {
371       if ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput != NULL) {
372         gBS->CloseEvent ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput);
373       }
374 
375       FreePool (UsbMouseAbsolutePointerDevice);
376       UsbMouseAbsolutePointerDevice = NULL;
377     }
378   }
379 
380 ErrorExit1:
381   gBS->RestoreTPL (OldTpl);
382 
383   return Status;
384 }
385 
386 
387 /**
388   Stop the USB mouse device handled by this driver.
389 
390   @param  This                   The 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        Absolute 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
USBMouseAbsolutePointerDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)402 USBMouseAbsolutePointerDriverBindingStop (
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_ABSOLUTE_POINTER_DEV  *UsbMouseAbsolutePointerDevice;
411   EFI_ABSOLUTE_POINTER_PROTOCOL   *AbsolutePointerProtocol;
412   EFI_USB_IO_PROTOCOL             *UsbIo;
413 
414   Status = gBS->OpenProtocol (
415                   Controller,
416                   &gEfiAbsolutePointerProtocolGuid,
417                   (VOID **) &AbsolutePointerProtocol,
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   UsbMouseAbsolutePointerDevice = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (AbsolutePointerProtocol);
428 
429   UsbIo = UsbMouseAbsolutePointerDevice->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     UsbMouseAbsolutePointerDevice->DevicePath
438     );
439 
440   //
441   // Delete the Asynchronous Interrupt Transfer from this device
442   //
443   UsbIo->UsbAsyncInterruptTransfer (
444            UsbIo,
445            UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
446            FALSE,
447            UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval,
448            0,
449            NULL,
450            NULL
451            );
452 
453   Status = gBS->UninstallProtocolInterface (
454                   Controller,
455                   &gEfiAbsolutePointerProtocolGuid,
456                   &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
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 (UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.WaitForInput);
473 
474   if (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent != NULL) {
475     gBS->CloseEvent (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent);
476     UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent = NULL;
477   }
478 
479   if (UsbMouseAbsolutePointerDevice->ControllerNameTable != NULL) {
480     FreeUnicodeStringTable (UsbMouseAbsolutePointerDevice->ControllerNameTable);
481   }
482 
483   FreePool (UsbMouseAbsolutePointerDevice);
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_ABSOLUTE_POINTER_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  UsbMouseAbsolutePointerDev   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 USB_MOUSE_ABSOLUTE_POINTER_DEV * UsbMouseAbsolutePointerDev)546 InitializeUsbMouseDevice (
547   IN  USB_MOUSE_ABSOLUTE_POINTER_DEV           *UsbMouseAbsolutePointerDev
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 = UsbMouseAbsolutePointerDev->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 == UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber) &&
610         (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseAbsolutePointerDev->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              UsbMouseAbsolutePointerDev->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              UsbMouseAbsolutePointerDev,
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   UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX = 1024;
670   UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY = 1024;
671   UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxZ = 0;
672   UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX = 0;
673   UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY = 0;
674   UsbMouseAbsolutePointerDev->Mode.AbsoluteMinZ = 0;
675   UsbMouseAbsolutePointerDev->Mode.Attributes   = 0x3;
676 
677   //
678   // Set boot protocol for the USB mouse.
679   // This driver only supports boot protocol.
680   //
681   UsbGetProtocolRequest (
682     UsbIo,
683     UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
684     &Protocol
685     );
686   if (Protocol != BOOT_PROTOCOL) {
687     Status = UsbSetProtocolRequest (
688                UsbIo,
689                UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
690                BOOT_PROTOCOL
691                );
692 
693     if (EFI_ERROR (Status)) {
694       FreePool (Buf);
695       FreePool (ReportDesc);
696       return Status;
697     }
698   }
699 
700   FreePool (Buf);
701   FreePool (ReportDesc);
702 
703   //
704   // Create event for delayed recovery, which deals with device error.
705   //
706   if (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent != NULL) {
707     gBS->CloseEvent (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent);
708     UsbMouseAbsolutePointerDev->DelayedRecoveryEvent = 0;
709   }
710 
711   gBS->CreateEvent (
712          EVT_TIMER | EVT_NOTIFY_SIGNAL,
713          TPL_NOTIFY,
714          USBMouseRecoveryHandler,
715          UsbMouseAbsolutePointerDev,
716          &UsbMouseAbsolutePointerDev->DelayedRecoveryEvent
717          );
718 
719   return EFI_SUCCESS;
720 }
721 
722 
723 /**
724   Handler function for USB mouse's asynchronous interrupt transfer.
725 
726   This function is the handler function for USB mouse's asynchronous interrupt transfer
727   to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
728   get button and movement state.
729 
730   @param  Data             A pointer to a buffer that is filled with key data which is
731                            retrieved via asynchronous interrupt transfer.
732   @param  DataLength       Indicates the size of the data buffer.
733   @param  Context          Pointing to USB_KB_DEV instance.
734   @param  Result           Indicates the result of the asynchronous interrupt transfer.
735 
736   @retval EFI_SUCCESS      Asynchronous interrupt transfer is handled successfully.
737   @retval EFI_DEVICE_ERROR Hardware error occurs.
738 
739 **/
740 EFI_STATUS
741 EFIAPI
OnMouseInterruptComplete(IN VOID * Data,IN UINTN DataLength,IN VOID * Context,IN UINT32 Result)742 OnMouseInterruptComplete (
743   IN  VOID        *Data,
744   IN  UINTN       DataLength,
745   IN  VOID        *Context,
746   IN  UINT32      Result
747   )
748 {
749   USB_MOUSE_ABSOLUTE_POINTER_DEV   *UsbMouseAbsolutePointerDevice;
750   EFI_USB_IO_PROTOCOL              *UsbIo;
751   UINT8                            EndpointAddr;
752   UINT32                           UsbResult;
753 
754   UsbMouseAbsolutePointerDevice  = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
755   UsbIo                          = UsbMouseAbsolutePointerDevice->UsbIo;
756 
757   if (Result != EFI_USB_NOERROR) {
758     //
759     // Some errors happen during the process
760     //
761     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
762       EFI_ERROR_CODE | EFI_ERROR_MINOR,
763       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
764       UsbMouseAbsolutePointerDevice->DevicePath
765       );
766 
767     if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
768       EndpointAddr = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
769 
770       UsbClearEndpointHalt (
771         UsbIo,
772         EndpointAddr,
773         &UsbResult
774         );
775     }
776 
777     //
778     // Delete & Submit this interrupt again
779     // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
780     //
781     UsbIo->UsbAsyncInterruptTransfer (
782              UsbIo,
783              UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
784              FALSE,
785              0,
786              0,
787              NULL,
788              NULL
789              );
790     //
791     // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
792     //
793     gBS->SetTimer (
794            UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent,
795            TimerRelative,
796            EFI_USB_INTERRUPT_DELAY
797            );
798     return EFI_DEVICE_ERROR;
799   }
800 
801   //
802   // If no error and no data, just return EFI_SUCCESS.
803   //
804   if (DataLength == 0 || Data == NULL) {
805     return EFI_SUCCESS;
806   }
807 
808   UsbMouseAbsolutePointerDevice->StateChanged = TRUE;
809 
810   //
811   // Check mouse Data
812   // USB HID Specification specifies following data format:
813   // Byte    Bits    Description
814   // 0       0       Button 1
815   //         1       Button 2
816   //         2       Button 3
817   //         4 to 7  Device-specific
818   // 1       0 to 7  X displacement
819   // 2       0 to 7  Y displacement
820   // 3 to n  0 to 7  Device specific (optional)
821   //
822   UsbMouseAbsolutePointerDevice->State.CurrentX += *((INT8 *) Data + 1);
823   UsbMouseAbsolutePointerDevice->State.CurrentY += *((INT8 *) Data + 2);
824 
825   if (DataLength > 3) {
826     UsbMouseAbsolutePointerDevice->State.CurrentZ += *((INT8 *) Data + 3);
827   }
828   UsbMouseAbsolutePointerDevice->State.ActiveButtons = *(UINT8 *) Data & (BIT0 | BIT1);
829 
830   return EFI_SUCCESS;
831 }
832 
833 /**
834   Retrieves the current state of a pointer device.
835 
836   @param  This                  A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
837   @param  MouseState            A pointer to the state information on the pointer device.
838 
839   @retval EFI_SUCCESS           The state of the pointer device was returned in State.
840   @retval EFI_NOT_READY         The state of the pointer device has not changed since the last call to
841                                 GetState().
842   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to retrieve the pointer device's
843                                 current state.
844   @retval EFI_INVALID_PARAMETER State is NULL.
845 
846 **/
847 EFI_STATUS
848 EFIAPI
GetMouseAbsolutePointerState(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,OUT EFI_ABSOLUTE_POINTER_STATE * State)849 GetMouseAbsolutePointerState (
850   IN   EFI_ABSOLUTE_POINTER_PROTOCOL  *This,
851   OUT  EFI_ABSOLUTE_POINTER_STATE     *State
852   )
853 {
854   USB_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
855 
856   if (State == NULL) {
857     return EFI_INVALID_PARAMETER;
858   }
859 
860   MouseAbsolutePointerDev = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
861 
862   if (!MouseAbsolutePointerDev->StateChanged) {
863     return EFI_NOT_READY;
864   }
865 
866   //
867   // Retrieve mouse state from USB_MOUSE_ABSOLUTE_POINTER_DEV,
868   // which was filled by OnMouseInterruptComplete()
869   //
870   CopyMem (
871     State,
872     &MouseAbsolutePointerDev->State,
873     sizeof (EFI_ABSOLUTE_POINTER_STATE)
874     );
875 
876   //
877   // Clear previous move state
878   //
879   MouseAbsolutePointerDev->State.CurrentX      = 0;
880   MouseAbsolutePointerDev->State.CurrentY      = 0;
881   MouseAbsolutePointerDev->State.CurrentZ      = 0;
882   MouseAbsolutePointerDev->State.ActiveButtons = 0;
883 
884   MouseAbsolutePointerDev->StateChanged = FALSE;
885 
886   return EFI_SUCCESS;
887 }
888 
889 
890 /**
891   Resets the pointer device hardware.
892 
893   @param  This                  A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
894   @param  ExtendedVerification  Indicates that the driver may perform a more exhaustive
895                                 verification operation of the device during reset.
896 
897   @retval EFI_SUCCESS           The device was reset.
898   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could not be reset.
899 
900 **/
901 EFI_STATUS
902 EFIAPI
UsbMouseAbsolutePointerReset(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,IN BOOLEAN ExtendedVerification)903 UsbMouseAbsolutePointerReset (
904   IN EFI_ABSOLUTE_POINTER_PROTOCOL  *This,
905   IN BOOLEAN                        ExtendedVerification
906   )
907 {
908   USB_MOUSE_ABSOLUTE_POINTER_DEV       *UsbMouseAbsolutePointerDevice;
909 
910   UsbMouseAbsolutePointerDevice  = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
911 
912   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
913     EFI_PROGRESS_CODE,
914     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
915     UsbMouseAbsolutePointerDevice->DevicePath
916     );
917 
918   //
919   // Clear mouse state.
920   //
921   ZeroMem (
922     &UsbMouseAbsolutePointerDevice->State,
923     sizeof (EFI_ABSOLUTE_POINTER_STATE)
924     );
925   UsbMouseAbsolutePointerDevice->StateChanged = FALSE;
926 
927   return EFI_SUCCESS;
928 }
929 
930 /**
931   Event notification function for EFI_ABSOLUTE_POINTER_PROTOCOL.WaitForInput event.
932 
933   @param  Event        Event to be signaled when there's input from mouse.
934   @param  Context      Points to USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
935 
936 **/
937 VOID
938 EFIAPI
UsbMouseAbsolutePointerWaitForInput(IN EFI_EVENT Event,IN VOID * Context)939 UsbMouseAbsolutePointerWaitForInput (
940   IN  EFI_EVENT               Event,
941   IN  VOID                    *Context
942   )
943 {
944   USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
945 
946   UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
947 
948   //
949   // If there's input from mouse, signal the event.
950   //
951   if (UsbMouseAbsolutePointerDev->StateChanged) {
952     gBS->SignalEvent (Event);
953   }
954 }
955 
956 /**
957   Handler for Delayed Recovery event.
958 
959   This function is the handler for Delayed Recovery event triggered
960   by timer.
961   After a device error occurs, the event would be triggered
962   with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
963   is defined in USB standard for error handling.
964 
965   @param  Event                 The Delayed Recovery event.
966   @param  Context               Points to the USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
967 
968 **/
969 VOID
970 EFIAPI
USBMouseRecoveryHandler(IN EFI_EVENT Event,IN VOID * Context)971 USBMouseRecoveryHandler (
972   IN    EFI_EVENT    Event,
973   IN    VOID         *Context
974   )
975 {
976   USB_MOUSE_ABSOLUTE_POINTER_DEV       *UsbMouseAbsolutePointerDev;
977   EFI_USB_IO_PROTOCOL                  *UsbIo;
978 
979   UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
980 
981   UsbIo       = UsbMouseAbsolutePointerDev->UsbIo;
982 
983   //
984   // Re-submit Asynchronous Interrupt Transfer for recovery.
985   //
986   UsbIo->UsbAsyncInterruptTransfer (
987            UsbIo,
988            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.EndpointAddress,
989            TRUE,
990            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.Interval,
991            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.MaxPacketSize,
992            OnMouseInterruptComplete,
993            UsbMouseAbsolutePointerDev
994            );
995 }
996