• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   USB Mouse Driver that manages USB mouse and produces Absolute Pointer Protocol.
3 
4 Copyright (c) 2004 - 2016, 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   // Let the cursor's starting position is in the center of the screen.
679   //
680   UsbMouseAbsolutePointerDev->State.CurrentX =
681     DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX, 2);
682   UsbMouseAbsolutePointerDev->State.CurrentY =
683     DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY, 2);
684 
685   //
686   // Set boot protocol for the USB mouse.
687   // This driver only supports boot protocol.
688   //
689   UsbGetProtocolRequest (
690     UsbIo,
691     UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
692     &Protocol
693     );
694   if (Protocol != BOOT_PROTOCOL) {
695     Status = UsbSetProtocolRequest (
696                UsbIo,
697                UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
698                BOOT_PROTOCOL
699                );
700 
701     if (EFI_ERROR (Status)) {
702       FreePool (Buf);
703       FreePool (ReportDesc);
704       return Status;
705     }
706   }
707 
708   FreePool (Buf);
709   FreePool (ReportDesc);
710 
711   //
712   // Create event for delayed recovery, which deals with device error.
713   //
714   if (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent != NULL) {
715     gBS->CloseEvent (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent);
716     UsbMouseAbsolutePointerDev->DelayedRecoveryEvent = 0;
717   }
718 
719   gBS->CreateEvent (
720          EVT_TIMER | EVT_NOTIFY_SIGNAL,
721          TPL_NOTIFY,
722          USBMouseRecoveryHandler,
723          UsbMouseAbsolutePointerDev,
724          &UsbMouseAbsolutePointerDev->DelayedRecoveryEvent
725          );
726 
727   return EFI_SUCCESS;
728 }
729 
730 
731 /**
732   Handler function for USB mouse's asynchronous interrupt transfer.
733 
734   This function is the handler function for USB mouse's asynchronous interrupt transfer
735   to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
736   get button and movement state.
737 
738   @param  Data             A pointer to a buffer that is filled with key data which is
739                            retrieved via asynchronous interrupt transfer.
740   @param  DataLength       Indicates the size of the data buffer.
741   @param  Context          Pointing to USB_KB_DEV instance.
742   @param  Result           Indicates the result of the asynchronous interrupt transfer.
743 
744   @retval EFI_SUCCESS      Asynchronous interrupt transfer is handled successfully.
745   @retval EFI_DEVICE_ERROR Hardware error occurs.
746 
747 **/
748 EFI_STATUS
749 EFIAPI
OnMouseInterruptComplete(IN VOID * Data,IN UINTN DataLength,IN VOID * Context,IN UINT32 Result)750 OnMouseInterruptComplete (
751   IN  VOID        *Data,
752   IN  UINTN       DataLength,
753   IN  VOID        *Context,
754   IN  UINT32      Result
755   )
756 {
757   USB_MOUSE_ABSOLUTE_POINTER_DEV   *UsbMouseAbsolutePointerDevice;
758   EFI_USB_IO_PROTOCOL              *UsbIo;
759   UINT8                            EndpointAddr;
760   UINT32                           UsbResult;
761 
762   UsbMouseAbsolutePointerDevice  = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
763   UsbIo                          = UsbMouseAbsolutePointerDevice->UsbIo;
764 
765   if (Result != EFI_USB_NOERROR) {
766     //
767     // Some errors happen during the process
768     //
769     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
770       EFI_ERROR_CODE | EFI_ERROR_MINOR,
771       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
772       UsbMouseAbsolutePointerDevice->DevicePath
773       );
774 
775     if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
776       EndpointAddr = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
777 
778       UsbClearEndpointHalt (
779         UsbIo,
780         EndpointAddr,
781         &UsbResult
782         );
783     }
784 
785     //
786     // Delete & Submit this interrupt again
787     // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
788     //
789     UsbIo->UsbAsyncInterruptTransfer (
790              UsbIo,
791              UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
792              FALSE,
793              0,
794              0,
795              NULL,
796              NULL
797              );
798     //
799     // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
800     //
801     gBS->SetTimer (
802            UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent,
803            TimerRelative,
804            EFI_USB_INTERRUPT_DELAY
805            );
806     return EFI_DEVICE_ERROR;
807   }
808 
809   //
810   // If no error and no data, just return EFI_SUCCESS.
811   //
812   if (DataLength == 0 || Data == NULL) {
813     return EFI_SUCCESS;
814   }
815 
816   UsbMouseAbsolutePointerDevice->StateChanged = TRUE;
817 
818   //
819   // Check mouse Data
820   // USB HID Specification specifies following data format:
821   // Byte    Bits    Description
822   // 0       0       Button 1
823   //         1       Button 2
824   //         2       Button 3
825   //         4 to 7  Device-specific
826   // 1       0 to 7  X displacement
827   // 2       0 to 7  Y displacement
828   // 3 to n  0 to 7  Device specific (optional)
829   //
830   UsbMouseAbsolutePointerDevice->State.ActiveButtons = *(UINT8 *) Data & (BIT0 | BIT1 | BIT2);
831 
832   UsbMouseAbsolutePointerDevice->State.CurrentX =
833     MIN (
834       MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentX + *((INT8 *) Data + 1),
835            (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX),
836       (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX
837       );
838   UsbMouseAbsolutePointerDevice->State.CurrentY =
839     MIN (
840       MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentY + *((INT8 *) Data + 2),
841            (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY),
842       (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY
843       );
844   if (DataLength > 3) {
845     UsbMouseAbsolutePointerDevice->State.CurrentZ =
846       MIN (
847         MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentZ + *((INT8 *) Data + 1),
848              (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinZ),
849         (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxZ
850         );
851   }
852 
853   return EFI_SUCCESS;
854 }
855 
856 /**
857   Retrieves the current state of a pointer device.
858 
859   @param  This                  A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
860   @param  MouseState            A pointer to the state information on the pointer device.
861 
862   @retval EFI_SUCCESS           The state of the pointer device was returned in State.
863   @retval EFI_NOT_READY         The state of the pointer device has not changed since the last call to
864                                 GetState().
865   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to retrieve the pointer device's
866                                 current state.
867   @retval EFI_INVALID_PARAMETER State is NULL.
868 
869 **/
870 EFI_STATUS
871 EFIAPI
GetMouseAbsolutePointerState(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,OUT EFI_ABSOLUTE_POINTER_STATE * State)872 GetMouseAbsolutePointerState (
873   IN   EFI_ABSOLUTE_POINTER_PROTOCOL  *This,
874   OUT  EFI_ABSOLUTE_POINTER_STATE     *State
875   )
876 {
877   USB_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
878 
879   if (State == NULL) {
880     return EFI_INVALID_PARAMETER;
881   }
882 
883   MouseAbsolutePointerDev = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
884 
885   if (!MouseAbsolutePointerDev->StateChanged) {
886     return EFI_NOT_READY;
887   }
888 
889   //
890   // Retrieve mouse state from USB_MOUSE_ABSOLUTE_POINTER_DEV,
891   // which was filled by OnMouseInterruptComplete()
892   //
893   CopyMem (
894     State,
895     &MouseAbsolutePointerDev->State,
896     sizeof (EFI_ABSOLUTE_POINTER_STATE)
897     );
898 
899   MouseAbsolutePointerDev->StateChanged = FALSE;
900 
901   return EFI_SUCCESS;
902 }
903 
904 
905 /**
906   Resets the pointer device hardware.
907 
908   @param  This                  A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
909   @param  ExtendedVerification  Indicates that the driver may perform a more exhaustive
910                                 verification operation of the device during reset.
911 
912   @retval EFI_SUCCESS           The device was reset.
913   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could not be reset.
914 
915 **/
916 EFI_STATUS
917 EFIAPI
UsbMouseAbsolutePointerReset(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,IN BOOLEAN ExtendedVerification)918 UsbMouseAbsolutePointerReset (
919   IN EFI_ABSOLUTE_POINTER_PROTOCOL  *This,
920   IN BOOLEAN                        ExtendedVerification
921   )
922 {
923   USB_MOUSE_ABSOLUTE_POINTER_DEV       *UsbMouseAbsolutePointerDevice;
924 
925   UsbMouseAbsolutePointerDevice  = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
926 
927   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
928     EFI_PROGRESS_CODE,
929     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
930     UsbMouseAbsolutePointerDevice->DevicePath
931     );
932 
933   //
934   // Clear mouse state.
935   //
936   ZeroMem (
937     &UsbMouseAbsolutePointerDevice->State,
938     sizeof (EFI_ABSOLUTE_POINTER_STATE)
939     );
940 
941   //
942   // Let the cursor's starting position is in the center of the screen.
943   //
944   UsbMouseAbsolutePointerDevice->State.CurrentX =
945     DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX, 2);
946   UsbMouseAbsolutePointerDevice->State.CurrentY =
947     DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY, 2);
948 
949   UsbMouseAbsolutePointerDevice->StateChanged = FALSE;
950 
951   return EFI_SUCCESS;
952 }
953 
954 /**
955   Event notification function for EFI_ABSOLUTE_POINTER_PROTOCOL.WaitForInput event.
956 
957   @param  Event        Event to be signaled when there's input from mouse.
958   @param  Context      Points to USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
959 
960 **/
961 VOID
962 EFIAPI
UsbMouseAbsolutePointerWaitForInput(IN EFI_EVENT Event,IN VOID * Context)963 UsbMouseAbsolutePointerWaitForInput (
964   IN  EFI_EVENT               Event,
965   IN  VOID                    *Context
966   )
967 {
968   USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
969 
970   UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
971 
972   //
973   // If there's input from mouse, signal the event.
974   //
975   if (UsbMouseAbsolutePointerDev->StateChanged) {
976     gBS->SignalEvent (Event);
977   }
978 }
979 
980 /**
981   Handler for Delayed Recovery event.
982 
983   This function is the handler for Delayed Recovery event triggered
984   by timer.
985   After a device error occurs, the event would be triggered
986   with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
987   is defined in USB standard for error handling.
988 
989   @param  Event                 The Delayed Recovery event.
990   @param  Context               Points to the USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
991 
992 **/
993 VOID
994 EFIAPI
USBMouseRecoveryHandler(IN EFI_EVENT Event,IN VOID * Context)995 USBMouseRecoveryHandler (
996   IN    EFI_EVENT    Event,
997   IN    VOID         *Context
998   )
999 {
1000   USB_MOUSE_ABSOLUTE_POINTER_DEV       *UsbMouseAbsolutePointerDev;
1001   EFI_USB_IO_PROTOCOL                  *UsbIo;
1002 
1003   UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
1004 
1005   UsbIo       = UsbMouseAbsolutePointerDev->UsbIo;
1006 
1007   //
1008   // Re-submit Asynchronous Interrupt Transfer for recovery.
1009   //
1010   UsbIo->UsbAsyncInterruptTransfer (
1011            UsbIo,
1012            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.EndpointAddress,
1013            TRUE,
1014            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.Interval,
1015            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.MaxPacketSize,
1016            OnMouseInterruptComplete,
1017            UsbMouseAbsolutePointerDev
1018            );
1019 }
1020