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