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