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