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