Do not draw anything during DrawLogo.
[edk2.git] / Nt32Pkg / WinNtSerialIoDxe / WinNtSerialIo.c
blob5a55fa428c0aa4fa8a9d710f6e3a44a9a7b7bf8d
1 /**@file
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 Module Name:
14 WinNtSerialIo.c
16 Abstract:
18 Our DriverBinding member functions operate on the handles
19 created by the NT Bus driver.
21 Handle(1) - WinNtIo - DevicePath(1)
23 If a serial port is added to the system this driver creates a new handle.
24 The new handle is required, since the serial device must add an UART device
25 pathnode.
27 Handle(2) - SerialIo - DevicePath(1)\UART
29 The driver then adds a gEfiWinNtSerialPortGuid as a protocol to Handle(1).
30 The instance data for this protocol is the private data used to create
31 Handle(2).
33 Handle(1) - WinNtIo - DevicePath(1) - WinNtSerialPort
35 If the driver is unloaded Handle(2) is removed from the system and
36 gEfiWinNtSerialPortGuid is removed from Handle(1).
38 Note: Handle(1) is any handle created by the Win NT Bus driver that is passed
39 into the DriverBinding member functions of this driver. This driver requires
40 a Handle(1) to contain a WinNtIo protocol, a DevicePath protocol, and
41 the TypeGuid in the WinNtIo must be gEfiWinNtSerialPortGuid.
43 If Handle(1) contains a gEfiWinNtSerialPortGuid protocol then the driver is
44 loaded on the device.
46 **/
48 #include "WinNtSerialIo.h"
50 EFI_DRIVER_BINDING_PROTOCOL gWinNtSerialIoDriverBinding = {
51 WinNtSerialIoDriverBindingSupported,
52 WinNtSerialIoDriverBindingStart,
53 WinNtSerialIoDriverBindingStop,
54 0xa,
55 NULL,
56 NULL
60 // List of supported baud rate
62 UINT64 mBaudRateCurrentSupport[] = {50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200, 38400, 57600, 115200, SERIAL_PORT_MAX_BAUD_RATE + 1};
64 /**
65 The user Entry Point for module WinNtSerialIo. The user code starts with this function.
67 @param[in] ImageHandle The firmware allocated handle for the EFI image.
68 @param[in] SystemTable A pointer to the EFI System Table.
70 @retval EFI_SUCCESS The entry point is executed successfully.
71 @retval other Some error occurs when executing this entry point.
73 **/
74 EFI_STATUS
75 EFIAPI
76 InitializeWinNtSerialIo(
77 IN EFI_HANDLE ImageHandle,
78 IN EFI_SYSTEM_TABLE *SystemTable
81 EFI_STATUS Status;
84 // Install driver model protocol(s).
86 Status = EfiLibInstallDriverBindingComponentName2 (
87 ImageHandle,
88 SystemTable,
89 &gWinNtSerialIoDriverBinding,
90 ImageHandle,
91 &gWinNtSerialIoComponentName,
92 &gWinNtSerialIoComponentName2
94 ASSERT_EFI_ERROR (Status);
97 return Status;
100 EFI_STATUS
101 EFIAPI
102 WinNtSerialIoDriverBindingSupported (
103 IN EFI_DRIVER_BINDING_PROTOCOL *This,
104 IN EFI_HANDLE Handle,
105 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
107 /*++
109 Routine Description:
111 Arguments:
113 Returns:
115 None
117 --*/
118 // TODO: This - add argument and description to function comment
119 // TODO: Handle - add argument and description to function comment
120 // TODO: RemainingDevicePath - add argument and description to function comment
121 // TODO: EFI_SUCCESS - add return value to function comment
122 // TODO: EFI_SUCCESS - add return value to function comment
124 EFI_STATUS Status;
125 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
126 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
127 UART_DEVICE_PATH *UartNode;
130 // Open the IO Abstraction(s) needed to perform the supported test
132 Status = gBS->OpenProtocol (
133 Handle,
134 &gEfiDevicePathProtocolGuid,
135 (VOID **) &ParentDevicePath,
136 This->DriverBindingHandle,
137 Handle,
138 EFI_OPEN_PROTOCOL_BY_DRIVER
140 if (Status == EFI_ALREADY_STARTED) {
141 return EFI_SUCCESS;
144 if (EFI_ERROR (Status)) {
145 return Status;
148 gBS->CloseProtocol (
149 Handle,
150 &gEfiDevicePathProtocolGuid,
151 This->DriverBindingHandle,
152 Handle
155 Status = gBS->OpenProtocol (
156 Handle,
157 &gEfiWinNtIoProtocolGuid,
158 (VOID **) &WinNtIo,
159 This->DriverBindingHandle,
160 Handle,
161 EFI_OPEN_PROTOCOL_BY_DRIVER
163 if (Status == EFI_ALREADY_STARTED) {
164 return EFI_SUCCESS;
167 if (EFI_ERROR (Status)) {
168 return Status;
172 // Make sure that the WinNt Thunk Protocol is valid
174 if (WinNtIo->WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
175 Status = EFI_UNSUPPORTED;
176 goto Error;
180 // Check the GUID to see if this is a handle type the driver supports
182 if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtSerialPortGuid)) {
183 Status = EFI_UNSUPPORTED;
184 goto Error;
187 if (RemainingDevicePath != NULL) {
188 Status = EFI_UNSUPPORTED;
189 UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
190 if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
191 UartNode->Header.SubType != MSG_UART_DP ||
192 DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) {
193 goto Error;
195 if ( UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
196 goto Error;
198 if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
199 goto Error;
201 if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
202 goto Error;
204 if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
205 goto Error;
207 if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
208 goto Error;
210 if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
211 goto Error;
213 Status = EFI_SUCCESS;
216 Error:
218 // Close the I/O Abstraction(s) used to perform the supported test
220 gBS->CloseProtocol (
221 Handle,
222 &gEfiWinNtIoProtocolGuid,
223 This->DriverBindingHandle,
224 Handle
227 return Status;
230 EFI_STATUS
231 EFIAPI
232 WinNtSerialIoDriverBindingStart (
233 IN EFI_DRIVER_BINDING_PROTOCOL *This,
234 IN EFI_HANDLE Handle,
235 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
237 /*++
239 Routine Description:
241 Arguments:
243 Returns:
245 None
247 --*/
248 // TODO: This - add argument and description to function comment
249 // TODO: Handle - add argument and description to function comment
250 // TODO: RemainingDevicePath - add argument and description to function comment
251 // TODO: EFI_SUCCESS - add return value to function comment
252 // TODO: EFI_SUCCESS - add return value to function comment
254 EFI_STATUS Status;
255 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
256 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
257 HANDLE NtHandle;
258 UART_DEVICE_PATH Node;
259 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
260 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
261 UINTN EntryCount;
262 UINTN Index;
263 EFI_SERIAL_IO_PROTOCOL *SerialIo;
265 Private = NULL;
266 NtHandle = INVALID_HANDLE_VALUE;
269 // Grab the protocols we need
271 Status = gBS->OpenProtocol (
272 Handle,
273 &gEfiDevicePathProtocolGuid,
274 (VOID **) &ParentDevicePath,
275 This->DriverBindingHandle,
276 Handle,
277 EFI_OPEN_PROTOCOL_BY_DRIVER
279 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
280 return Status;
284 // Grab the IO abstraction we need to get any work done
286 Status = gBS->OpenProtocol (
287 Handle,
288 &gEfiWinNtIoProtocolGuid,
289 (VOID **) &WinNtIo,
290 This->DriverBindingHandle,
291 Handle,
292 EFI_OPEN_PROTOCOL_BY_DRIVER
294 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
295 gBS->CloseProtocol (
296 Handle,
297 &gEfiDevicePathProtocolGuid,
298 This->DriverBindingHandle,
299 Handle
301 return Status;
304 if (Status == EFI_ALREADY_STARTED) {
306 if (RemainingDevicePath == NULL) {
307 return EFI_SUCCESS;
311 // Make sure a child handle does not already exist. This driver can only
312 // produce one child per serial port.
314 Status = gBS->OpenProtocolInformation (
315 Handle,
316 &gEfiWinNtIoProtocolGuid,
317 &OpenInfoBuffer,
318 &EntryCount
320 if (EFI_ERROR (Status)) {
321 return Status;
324 Status = EFI_ALREADY_STARTED;
325 for (Index = 0; Index < EntryCount; Index++) {
326 if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
327 Status = gBS->OpenProtocol (
328 OpenInfoBuffer[Index].ControllerHandle,
329 &gEfiSerialIoProtocolGuid,
330 (VOID **) &SerialIo,
331 This->DriverBindingHandle,
332 Handle,
333 EFI_OPEN_PROTOCOL_GET_PROTOCOL
335 if (!EFI_ERROR (Status)) {
336 CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
337 Status = SerialIo->SetAttributes (
338 SerialIo,
339 Node.BaudRate,
340 SerialIo->Mode->ReceiveFifoDepth,
341 SerialIo->Mode->Timeout,
342 (EFI_PARITY_TYPE)Node.Parity,
343 Node.DataBits,
344 (EFI_STOP_BITS_TYPE)Node.StopBits
347 break;
351 FreePool (OpenInfoBuffer);
352 return Status;
356 // Check to see if we can access the hardware device. If it's Open in NT we
357 // will not get access.
359 NtHandle = WinNtIo->WinNtThunk->CreateFile (
360 WinNtIo->EnvString,
361 GENERIC_READ | GENERIC_WRITE,
363 NULL,
364 OPEN_EXISTING,
366 NULL
368 if (NtHandle == INVALID_HANDLE_VALUE) {
369 Status = EFI_DEVICE_ERROR;
370 goto Error;
374 // Construct Private data
376 Private = AllocatePool (sizeof (WIN_NT_SERIAL_IO_PRIVATE_DATA));
377 if (Private == NULL) {
378 goto Error;
382 // This signature must be valid before any member function is called
384 Private->Signature = WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
385 Private->NtHandle = NtHandle;
386 Private->ControllerHandle = Handle;
387 Private->Handle = NULL;
388 Private->WinNtThunk = WinNtIo->WinNtThunk;
389 Private->ParentDevicePath = ParentDevicePath;
390 Private->ControllerNameTable = NULL;
392 Private->SoftwareLoopbackEnable = FALSE;
393 Private->HardwareLoopbackEnable = FALSE;
394 Private->HardwareFlowControl = FALSE;
395 Private->Fifo.First = 0;
396 Private->Fifo.Last = 0;
397 Private->Fifo.Surplus = SERIAL_MAX_BUFFER_SIZE;
399 AddUnicodeString2 (
400 "eng",
401 gWinNtSerialIoComponentName.SupportedLanguages,
402 &Private->ControllerNameTable,
403 WinNtIo->EnvString,
404 TRUE
406 AddUnicodeString2 (
407 "en",
408 gWinNtSerialIoComponentName2.SupportedLanguages,
409 &Private->ControllerNameTable,
410 WinNtIo->EnvString,
411 FALSE
415 Private->SerialIo.Revision = SERIAL_IO_INTERFACE_REVISION;
416 Private->SerialIo.Reset = WinNtSerialIoReset;
417 Private->SerialIo.SetAttributes = WinNtSerialIoSetAttributes;
418 Private->SerialIo.SetControl = WinNtSerialIoSetControl;
419 Private->SerialIo.GetControl = WinNtSerialIoGetControl;
420 Private->SerialIo.Write = WinNtSerialIoWrite;
421 Private->SerialIo.Read = WinNtSerialIoRead;
422 Private->SerialIo.Mode = &Private->SerialIoMode;
424 if (RemainingDevicePath != NULL) {
426 // Match the configuration of the RemainingDevicePath. IsHandleSupported()
427 // already checked to make sure the RemainingDevicePath contains settings
428 // that we can support.
430 CopyMem (&Private->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
431 } else {
433 // Build the device path by appending the UART node to the ParentDevicePath
434 // from the WinNtIo handle. The Uart setings are zero here, since
435 // SetAttribute() will update them to match the default setings.
437 ZeroMem (&Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
438 Private->UartDevicePath.Header.Type = MESSAGING_DEVICE_PATH;
439 Private->UartDevicePath.Header.SubType = MSG_UART_DP;
440 SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
444 // Build the device path by appending the UART node to the ParentDevicePath
445 // from the WinNtIo handle. The Uart setings are zero here, since
446 // SetAttribute() will update them to match the current setings.
448 Private->DevicePath = AppendDevicePathNode (
449 ParentDevicePath,
450 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
452 if (Private->DevicePath == NULL) {
453 Status = EFI_OUT_OF_RESOURCES;
454 goto Error;
458 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
460 Private->SerialIoMode.ControlMask = SERIAL_CONTROL_MASK;
461 Private->SerialIoMode.Timeout = SERIAL_TIMEOUT_DEFAULT;
462 Private->SerialIoMode.BaudRate = Private->UartDevicePath.BaudRate;
463 Private->SerialIoMode.ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
464 Private->SerialIoMode.DataBits = Private->UartDevicePath.DataBits;
465 Private->SerialIoMode.Parity = Private->UartDevicePath.Parity;
466 Private->SerialIoMode.StopBits = Private->UartDevicePath.StopBits;
469 // Issue a reset to initialize the COM port
471 Status = Private->SerialIo.Reset (&Private->SerialIo);
472 if (EFI_ERROR (Status)) {
473 goto Error;
477 // Create new child handle
479 Status = gBS->InstallMultipleProtocolInterfaces (
480 &Private->Handle,
481 &gEfiSerialIoProtocolGuid,
482 &Private->SerialIo,
483 &gEfiDevicePathProtocolGuid,
484 Private->DevicePath,
485 NULL
487 if (EFI_ERROR (Status)) {
488 goto Error;
492 // Open For Child Device
494 Status = gBS->OpenProtocol (
495 Handle,
496 &gEfiWinNtIoProtocolGuid,
497 (VOID **) &WinNtIo,
498 This->DriverBindingHandle,
499 Private->Handle,
500 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
502 if (EFI_ERROR (Status)) {
503 goto Error;
506 return EFI_SUCCESS;
508 Error:
510 // Use the Stop() function to free all resources allocated in Start()
512 if (Private != NULL) {
513 if (Private->Handle != NULL) {
514 This->Stop (This, Handle, 1, &Private->Handle);
515 } else {
516 if (NtHandle != INVALID_HANDLE_VALUE) {
517 Private->WinNtThunk->CloseHandle (NtHandle);
520 if (Private->DevicePath != NULL) {
521 FreePool (Private->DevicePath);
524 FreeUnicodeStringTable (Private->ControllerNameTable);
526 FreePool (Private);
530 This->Stop (This, Handle, 0, NULL);
532 return Status;
535 EFI_STATUS
536 EFIAPI
537 WinNtSerialIoDriverBindingStop (
538 IN EFI_DRIVER_BINDING_PROTOCOL *This,
539 IN EFI_HANDLE Handle,
540 IN UINTN NumberOfChildren,
541 IN EFI_HANDLE *ChildHandleBuffer
543 /*++
545 Routine Description:
547 TODO: Add function description
549 Arguments:
551 This - TODO: add argument description
552 Handle - TODO: add argument description
553 NumberOfChildren - TODO: add argument description
554 ChildHandleBuffer - TODO: add argument description
556 Returns:
558 EFI_DEVICE_ERROR - TODO: Add description for return value
559 EFI_SUCCESS - TODO: Add description for return value
561 --*/
563 EFI_STATUS Status;
564 UINTN Index;
565 BOOLEAN AllChildrenStopped;
566 EFI_SERIAL_IO_PROTOCOL *SerialIo;
567 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
568 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
571 // Complete all outstanding transactions to Controller.
572 // Don't allow any new transaction to Controller to be started.
575 if (NumberOfChildren == 0) {
577 // Close the bus driver
579 Status = gBS->CloseProtocol (
580 Handle,
581 &gEfiWinNtIoProtocolGuid,
582 This->DriverBindingHandle,
583 Handle
585 Status = gBS->CloseProtocol (
586 Handle,
587 &gEfiDevicePathProtocolGuid,
588 This->DriverBindingHandle,
589 Handle
591 return Status;
594 AllChildrenStopped = TRUE;
596 for (Index = 0; Index < NumberOfChildren; Index++) {
597 Status = gBS->OpenProtocol (
598 ChildHandleBuffer[Index],
599 &gEfiSerialIoProtocolGuid,
600 (VOID **) &SerialIo,
601 This->DriverBindingHandle,
602 Handle,
603 EFI_OPEN_PROTOCOL_GET_PROTOCOL
605 if (!EFI_ERROR (Status)) {
606 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo);
608 ASSERT (Private->Handle == ChildHandleBuffer[Index]);
610 Status = gBS->CloseProtocol (
611 Handle,
612 &gEfiWinNtIoProtocolGuid,
613 This->DriverBindingHandle,
614 ChildHandleBuffer[Index]
617 Status = gBS->UninstallMultipleProtocolInterfaces (
618 ChildHandleBuffer[Index],
619 &gEfiSerialIoProtocolGuid,
620 &Private->SerialIo,
621 &gEfiDevicePathProtocolGuid,
622 Private->DevicePath,
623 NULL
626 if (EFI_ERROR (Status)) {
627 gBS->OpenProtocol (
628 Handle,
629 &gEfiWinNtIoProtocolGuid,
630 (VOID **) &WinNtIo,
631 This->DriverBindingHandle,
632 ChildHandleBuffer[Index],
633 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
635 } else {
636 Private->WinNtThunk->CloseHandle (Private->NtHandle);
638 FreePool (Private->DevicePath);
640 FreeUnicodeStringTable (Private->ControllerNameTable);
642 FreePool (Private);
646 if (EFI_ERROR (Status)) {
647 AllChildrenStopped = FALSE;
651 if (!AllChildrenStopped) {
652 return EFI_DEVICE_ERROR;
655 return EFI_SUCCESS;
659 // Serial IO Protocol member functions
662 EFI_STATUS
663 EFIAPI
664 WinNtSerialIoReset (
665 IN EFI_SERIAL_IO_PROTOCOL *This
667 /*++
669 Routine Description:
671 TODO: Add function description
673 Arguments:
675 This - TODO: add argument description
677 Returns:
679 TODO: add return values
681 --*/
683 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
684 EFI_TPL Tpl;
686 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
688 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
690 Private->WinNtThunk->PurgeComm (
691 Private->NtHandle,
692 PURGE_TXCLEAR | PURGE_RXCLEAR
695 gBS->RestoreTPL (Tpl);
697 return This->SetAttributes (
698 This,
699 This->Mode->BaudRate,
700 This->Mode->ReceiveFifoDepth,
701 This->Mode->Timeout,
702 (EFI_PARITY_TYPE)This->Mode->Parity,
703 (UINT8) This->Mode->DataBits,
704 (EFI_STOP_BITS_TYPE)This->Mode->StopBits
708 EFI_STATUS
709 EFIAPI
710 WinNtSerialIoSetAttributes (
711 IN EFI_SERIAL_IO_PROTOCOL *This,
712 IN UINT64 BaudRate,
713 IN UINT32 ReceiveFifoDepth,
714 IN UINT32 Timeout,
715 IN EFI_PARITY_TYPE Parity,
716 IN UINT8 DataBits,
717 IN EFI_STOP_BITS_TYPE StopBits
719 /*++
721 Routine Description:
723 This function is used to set the attributes.
725 Arguments:
727 This - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue.
728 BaudRate - The Baud rate of the serial device.
729 ReceiveFifoDepth - The request depth of fifo on receive side.
730 Timeout - the request timeout for a single charact.
731 Parity - The type of parity used in serial device.
732 DataBits - Number of deata bits used in serial device.
733 StopBits - Number of stop bits used in serial device.
735 Returns:
736 Status code
738 None
740 --*/
741 // TODO: EFI_SUCCESS - add return value to function comment
742 // TODO: EFI_DEVICE_ERROR - add return value to function comment
743 // TODO: EFI_DEVICE_ERROR - add return value to function comment
744 // TODO: EFI_DEVICE_ERROR - add return value to function comment
745 // TODO: EFI_SUCCESS - add return value to function comment
746 // TODO: EFI_DEVICE_ERROR - add return value to function comment
747 // TODO: EFI_SUCCESS - add return value to function comment
749 EFI_STATUS Status;
750 UINTN Index;
751 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
752 COMMTIMEOUTS PortTimeOuts;
753 DWORD ConvertedTime;
754 BOOL Result;
755 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
756 EFI_TPL Tpl;
758 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
761 // Some of our arguments have defaults if a null value is passed in, and
762 // we must set the default values if a null argument is passed in.
764 if (BaudRate == 0) {
765 BaudRate = FixedPcdGet64 (PcdUartDefaultBaudRate);
768 if (ReceiveFifoDepth == 0) {
769 ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
772 if (Timeout == 0) {
773 Timeout = SERIAL_TIMEOUT_DEFAULT;
776 if (Parity == DefaultParity) {
777 Parity = (EFI_PARITY_TYPE) (FixedPcdGet8 (PcdUartDefaultParity));
780 if (DataBits == 0) {
781 DataBits = FixedPcdGet8 (PcdUartDefaultDataBits);
784 if (StopBits == DefaultStopBits) {
785 StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits);
789 // Make sure all parameters are valid
791 if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
792 return EFI_INVALID_PARAMETER;
796 //The lower baud rate supported by the serial device will be selected without exceeding the unsupported BaudRate parameter
799 for (Index = 1; Index < (sizeof (mBaudRateCurrentSupport) / sizeof (mBaudRateCurrentSupport[0])); Index++) {
800 if (BaudRate < mBaudRateCurrentSupport[Index]) {
801 BaudRate = mBaudRateCurrentSupport[Index-1];
802 break;
806 if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {
807 return EFI_INVALID_PARAMETER;
810 if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
811 return EFI_INVALID_PARAMETER;
814 if ((Parity < NoParity) || (Parity > SpaceParity)) {
815 return EFI_INVALID_PARAMETER;
818 if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
819 return EFI_INVALID_PARAMETER;
823 // Now we only support DataBits=7,8.
825 if ((DataBits < 7) || (DataBits > 8)) {
826 return EFI_INVALID_PARAMETER;
830 // Now we only support DataBits=7,8.
831 // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits.
833 if (StopBits == OneFiveStopBits) {
834 return EFI_INVALID_PARAMETER;
838 // See if the new attributes already match the current attributes
840 if (Private->UartDevicePath.BaudRate == BaudRate &&
841 Private->UartDevicePath.DataBits == DataBits &&
842 Private->UartDevicePath.Parity == Parity &&
843 Private->UartDevicePath.StopBits == StopBits &&
844 Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth &&
845 Private->SerialIoMode.Timeout == Timeout ) {
846 return EFI_SUCCESS;
849 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
852 // Get current values from NT
854 ZeroMem (&Private->NtDCB, sizeof (DCB));
855 Private->NtDCB.DCBlength = sizeof (DCB);
857 if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Private->NtDCB)) {
858 Private->NtError = Private->WinNtThunk->GetLastError ();
859 DEBUG ((EFI_D_ERROR, "SerialSetAttributes: GetCommState %d\n", Private->NtError));
860 gBS->RestoreTPL (Tpl);
861 return EFI_DEVICE_ERROR;
865 // Map EFI com setting to NT
867 Private->NtDCB.BaudRate = ConvertBaud2Nt (BaudRate);
868 Private->NtDCB.ByteSize = ConvertData2Nt (DataBits);
869 Private->NtDCB.Parity = ConvertParity2Nt (Parity);
870 Private->NtDCB.StopBits = ConvertStop2Nt (StopBits);
872 Private->NtDCB.fBinary = TRUE;
873 Private->NtDCB.fParity = Private->NtDCB.Parity == NOPARITY ? FALSE : TRUE;
874 Private->NtDCB.fOutxCtsFlow = FALSE;
875 Private->NtDCB.fOutxDsrFlow = FALSE;
876 Private->NtDCB.fDtrControl = DTR_CONTROL_ENABLE;
877 Private->NtDCB.fDsrSensitivity = FALSE;
878 Private->NtDCB.fOutX = FALSE;
879 Private->NtDCB.fInX = FALSE;
880 Private->NtDCB.fRtsControl = RTS_CONTROL_ENABLE;
881 Private->NtDCB.fNull = FALSE;
884 // Set new values
886 Result = Private->WinNtThunk->SetCommState (Private->NtHandle, &Private->NtDCB);
887 if (!Result) {
888 Private->NtError = Private->WinNtThunk->GetLastError ();
889 DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommState %d\n", Private->NtError));
890 gBS->RestoreTPL (Tpl);
891 return EFI_DEVICE_ERROR;
895 // Set com port read/write timeout values
897 ConvertedTime = ConvertTime2Nt (Timeout);
898 PortTimeOuts.ReadIntervalTimeout = MAXDWORD;
899 PortTimeOuts.ReadTotalTimeoutMultiplier = 0;
900 PortTimeOuts.ReadTotalTimeoutConstant = ConvertedTime;
901 PortTimeOuts.WriteTotalTimeoutMultiplier = ConvertedTime == 0 ? 1 : ConvertedTime;
902 PortTimeOuts.WriteTotalTimeoutConstant = 0;
904 if (!Private->WinNtThunk->SetCommTimeouts (Private->NtHandle, &PortTimeOuts)) {
905 Private->NtError = Private->WinNtThunk->GetLastError ();
906 DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommTimeouts %d\n", Private->NtError));
907 gBS->RestoreTPL (Tpl);
908 return EFI_DEVICE_ERROR;
912 // Update mode
914 Private->SerialIoMode.BaudRate = BaudRate;
915 Private->SerialIoMode.ReceiveFifoDepth = ReceiveFifoDepth;
916 Private->SerialIoMode.Timeout = Timeout;
917 Private->SerialIoMode.Parity = Parity;
918 Private->SerialIoMode.DataBits = DataBits;
919 Private->SerialIoMode.StopBits = StopBits;
922 // See if Device Path Node has actually changed
924 if (Private->UartDevicePath.BaudRate == BaudRate &&
925 Private->UartDevicePath.DataBits == DataBits &&
926 Private->UartDevicePath.Parity == Parity &&
927 Private->UartDevicePath.StopBits == StopBits ) {
928 gBS->RestoreTPL(Tpl);
929 return EFI_SUCCESS;
933 // Update the device path
935 Private->UartDevicePath.BaudRate = BaudRate;
936 Private->UartDevicePath.DataBits = DataBits;
937 Private->UartDevicePath.Parity = (UINT8) Parity;
938 Private->UartDevicePath.StopBits = (UINT8) StopBits;
940 NewDevicePath = AppendDevicePathNode (
941 Private->ParentDevicePath,
942 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
944 if (NewDevicePath == NULL) {
945 gBS->RestoreTPL (Tpl);
946 return EFI_DEVICE_ERROR;
949 if (Private->Handle != NULL) {
950 Status = gBS->ReinstallProtocolInterface (
951 Private->Handle,
952 &gEfiDevicePathProtocolGuid,
953 Private->DevicePath,
954 NewDevicePath
956 if (EFI_ERROR (Status)) {
957 gBS->RestoreTPL (Tpl);
958 return Status;
962 if (Private->DevicePath != NULL) {
963 FreePool (Private->DevicePath);
966 Private->DevicePath = NewDevicePath;
968 gBS->RestoreTPL (Tpl);
970 return EFI_SUCCESS;
973 EFI_STATUS
974 EFIAPI
975 WinNtSerialIoSetControl (
976 IN EFI_SERIAL_IO_PROTOCOL *This,
977 IN UINT32 Control
979 /*++
981 Routine Description:
983 TODO: Add function description
985 Arguments:
987 This - TODO: add argument description
988 Control - TODO: add argument description
990 Returns:
992 EFI_DEVICE_ERROR - TODO: Add description for return value
993 EFI_DEVICE_ERROR - TODO: Add description for return value
994 EFI_SUCCESS - TODO: Add description for return value
996 --*/
998 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
999 BOOL Result;
1000 DCB Dcb;
1001 EFI_TPL Tpl;
1004 // first determine the parameter is invalid
1006 if (Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
1007 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
1008 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) {
1009 return EFI_UNSUPPORTED;
1012 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1014 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1016 Result = Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb);
1018 if (!Result) {
1019 Private->NtError = Private->WinNtThunk->GetLastError ();
1020 DEBUG ((EFI_D_ERROR, "SerialSetControl: GetCommState %d\n", Private->NtError));
1021 gBS->RestoreTPL (Tpl);
1022 return EFI_DEVICE_ERROR;
1025 Dcb.fRtsControl = RTS_CONTROL_DISABLE;
1026 Dcb.fDtrControl = DTR_CONTROL_DISABLE;
1027 Private->HardwareFlowControl = FALSE;
1028 Private->SoftwareLoopbackEnable = FALSE;
1029 Private->HardwareLoopbackEnable = FALSE;
1031 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
1032 Dcb.fRtsControl = RTS_CONTROL_ENABLE;
1035 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
1036 Dcb.fDtrControl = DTR_CONTROL_ENABLE;
1039 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
1040 Private->HardwareFlowControl = TRUE;
1043 if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
1044 Private->SoftwareLoopbackEnable = TRUE;
1047 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
1048 Private->HardwareLoopbackEnable = TRUE;
1051 Result = Private->WinNtThunk->SetCommState (
1052 Private->NtHandle,
1053 &Dcb
1056 if (!Result) {
1057 Private->NtError = Private->WinNtThunk->GetLastError ();
1058 DEBUG ((EFI_D_ERROR, "SerialSetControl: SetCommState %d\n", Private->NtError));
1059 gBS->RestoreTPL (Tpl);
1060 return EFI_DEVICE_ERROR;
1063 gBS->RestoreTPL (Tpl);
1065 return EFI_SUCCESS;
1068 EFI_STATUS
1069 EFIAPI
1070 WinNtSerialIoGetControl (
1071 IN EFI_SERIAL_IO_PROTOCOL *This,
1072 OUT UINT32 *Control
1074 /*++
1076 Routine Description:
1078 TODO: Add function description
1080 Arguments:
1082 This - TODO: add argument description
1083 Control - TODO: add argument description
1085 Returns:
1087 EFI_DEVICE_ERROR - TODO: Add description for return value
1088 EFI_DEVICE_ERROR - TODO: Add description for return value
1089 EFI_DEVICE_ERROR - TODO: Add description for return value
1090 EFI_SUCCESS - TODO: Add description for return value
1092 --*/
1094 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1095 DWORD ModemStatus;
1096 DWORD Errors;
1097 UINT32 Bits;
1098 DCB Dcb;
1099 EFI_TPL Tpl;
1101 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1103 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1106 // Get modem status
1108 if (!Private->WinNtThunk->GetCommModemStatus (Private->NtHandle, &ModemStatus)) {
1109 Private->NtError = Private->WinNtThunk->GetLastError ();
1110 gBS->RestoreTPL (Tpl);
1111 return EFI_DEVICE_ERROR;
1114 Bits = 0;
1115 if (ModemStatus & MS_CTS_ON) {
1116 Bits |= EFI_SERIAL_CLEAR_TO_SEND;
1119 if (ModemStatus & MS_DSR_ON) {
1120 Bits |= EFI_SERIAL_DATA_SET_READY;
1123 if (ModemStatus & MS_RING_ON) {
1124 Bits |= EFI_SERIAL_RING_INDICATE;
1127 if (ModemStatus & MS_RLSD_ON) {
1128 Bits |= EFI_SERIAL_CARRIER_DETECT;
1132 // Get ctrl status
1134 if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb)) {
1135 Private->NtError = Private->WinNtThunk->GetLastError ();
1136 DEBUG ((EFI_D_ERROR, "SerialGetControl: GetCommState %d\n", Private->NtError));
1137 gBS->RestoreTPL (Tpl);
1138 return EFI_DEVICE_ERROR;
1141 if (Dcb.fDtrControl == DTR_CONTROL_ENABLE) {
1142 Bits |= EFI_SERIAL_DATA_TERMINAL_READY;
1145 if (Dcb.fRtsControl == RTS_CONTROL_ENABLE) {
1146 Bits |= EFI_SERIAL_REQUEST_TO_SEND;
1149 if (Private->HardwareFlowControl) {
1150 Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1153 if (Private->SoftwareLoopbackEnable) {
1154 Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1157 if (Private->HardwareLoopbackEnable) {
1158 Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1162 // Get input buffer status
1164 if (!Private->WinNtThunk->ClearCommError (Private->NtHandle, &Errors, &Private->NtComStatus)) {
1165 Private->NtError = Private->WinNtThunk->GetLastError ();
1166 DEBUG ((EFI_D_ERROR, "SerialGetControl: ClearCommError %d\n", Private->NtError));
1167 gBS->RestoreTPL (Tpl);
1168 return EFI_DEVICE_ERROR;
1171 if (Private->NtComStatus.cbInQue == 0) {
1172 Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1175 *Control = Bits;
1177 gBS->RestoreTPL (Tpl);
1179 return EFI_SUCCESS;
1182 EFI_STATUS
1183 EFIAPI
1184 WinNtSerialIoWrite (
1185 IN EFI_SERIAL_IO_PROTOCOL *This,
1186 IN OUT UINTN *BufferSize,
1187 IN VOID *Buffer
1189 /*++
1191 Routine Description:
1193 TODO: Add function description
1195 Arguments:
1197 This - TODO: add argument description
1198 BufferSize - TODO: add argument description
1199 Buffer - TODO: add argument description
1201 Returns:
1203 EFI_DEVICE_ERROR - TODO: Add description for return value
1204 EFI_SUCCESS - TODO: Add description for return value
1206 --*/
1208 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1209 UINT8 *ByteBuffer;
1210 UINTN TotalBytesWritten;
1211 DWORD BytesToGo;
1212 DWORD BytesWritten;
1213 BOOL Result;
1214 UINT32 Index;
1215 UINT32 Control;
1216 EFI_TPL Tpl;
1218 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1220 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1222 ByteBuffer = (UINT8 *) Buffer;
1223 TotalBytesWritten = 0;
1225 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1226 for (Index = 0; Index < *BufferSize; Index++) {
1227 if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) {
1228 TotalBytesWritten++;
1229 } else {
1230 break;
1233 } else {
1234 BytesToGo = (DWORD) (*BufferSize);
1236 do {
1237 if (Private->HardwareFlowControl) {
1239 // Send RTS
1241 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1242 Control |= EFI_SERIAL_REQUEST_TO_SEND;
1243 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1247 // Do the write
1249 Result = Private->WinNtThunk->WriteFile (
1250 Private->NtHandle,
1251 &ByteBuffer[TotalBytesWritten],
1252 BytesToGo,
1253 &BytesWritten,
1254 NULL
1257 if (Private->HardwareFlowControl) {
1259 // Assert RTS
1261 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1262 Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND;
1263 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1266 TotalBytesWritten += BytesWritten;
1267 BytesToGo -= BytesWritten;
1268 if (!Result) {
1269 Private->NtError = Private->WinNtThunk->GetLastError ();
1270 DEBUG ((EFI_D_ERROR, "SerialWrite: FileWrite %d\n", Private->NtError));
1271 *BufferSize = TotalBytesWritten;
1272 gBS->RestoreTPL (Tpl);
1273 return EFI_DEVICE_ERROR;
1275 } while (BytesToGo > 0);
1278 *BufferSize = TotalBytesWritten;
1280 gBS->RestoreTPL (Tpl);
1282 return EFI_SUCCESS;
1285 EFI_STATUS
1286 EFIAPI
1287 WinNtSerialIoRead (
1288 IN EFI_SERIAL_IO_PROTOCOL *This,
1289 IN OUT UINTN *BufferSize,
1290 OUT VOID *Buffer
1292 /*++
1294 Routine Description:
1296 TODO: Add function description
1298 Arguments:
1300 This - TODO: add argument description
1301 BufferSize - TODO: add argument description
1302 Buffer - TODO: add argument description
1304 Returns:
1306 EFI_DEVICE_ERROR - TODO: Add description for return value
1308 --*/
1310 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1311 BOOL Result;
1312 DWORD BytesRead;
1313 EFI_STATUS Status;
1314 UINT32 Index;
1315 UINT8 Data;
1316 UINT32 Control;
1317 EFI_TPL Tpl;
1319 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1321 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1324 // Do the read
1326 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1327 for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) {
1328 if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) {
1329 ((UINT8 *) Buffer)[Index] = Data;
1330 BytesRead++;
1331 } else {
1332 break;
1335 } else {
1336 if (Private->HardwareFlowControl) {
1337 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1338 Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1339 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1342 Result = Private->WinNtThunk->ReadFile (
1343 Private->NtHandle,
1344 Buffer,
1345 (DWORD) *BufferSize,
1346 &BytesRead,
1347 NULL
1350 if (Private->HardwareFlowControl) {
1351 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1352 Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY;
1353 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1356 if (!Result) {
1357 Private->NtError = Private->WinNtThunk->GetLastError ();
1358 gBS->RestoreTPL (Tpl);
1359 return EFI_DEVICE_ERROR;
1363 if (BytesRead != *BufferSize) {
1364 Status = EFI_TIMEOUT;
1365 } else {
1366 Status = EFI_SUCCESS;
1369 *BufferSize = (UINTN) BytesRead;
1371 gBS->RestoreTPL (Tpl);
1373 return Status;
1376 BOOLEAN
1377 IsaSerialFifoFull (
1378 IN SERIAL_DEV_FIFO *Fifo
1380 /*++
1382 Routine Description:
1383 Detect whether specific FIFO is full or not
1385 Arguments:
1386 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1388 Returns:
1389 TRUE: the FIFO is full
1390 FALSE: the FIFO is not full
1392 --*/
1394 if (Fifo->Surplus == 0) {
1395 return TRUE;
1398 return FALSE;
1401 BOOLEAN
1402 IsaSerialFifoEmpty (
1403 IN SERIAL_DEV_FIFO *Fifo
1405 /*++
1407 Routine Description:
1408 Detect whether specific FIFO is empty or not
1410 Arguments:
1411 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1413 Returns:
1414 TRUE: the FIFO is empty
1415 FALSE: the FIFO is not empty
1417 --*/
1419 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
1420 return TRUE;
1423 return FALSE;
1426 EFI_STATUS
1427 IsaSerialFifoAdd (
1428 IN SERIAL_DEV_FIFO *Fifo,
1429 IN UINT8 Data
1431 /*++
1433 Routine Description:
1434 Add data to specific FIFO
1436 Arguments:
1437 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1438 Data UINT8: the data added to FIFO
1440 Returns:
1441 EFI_SUCCESS: Add data to specific FIFO successfully
1442 EFI_OUT_RESOURCE: Failed to add data because FIFO is already full
1444 --*/
1445 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1448 // if FIFO full can not add data
1450 if (IsaSerialFifoFull (Fifo)) {
1451 return EFI_OUT_OF_RESOURCES;
1455 // FIFO is not full can add data
1457 Fifo->Data[Fifo->Last] = Data;
1458 Fifo->Surplus--;
1459 Fifo->Last++;
1460 if (Fifo->Last >= SERIAL_MAX_BUFFER_SIZE) {
1461 Fifo->Last = 0;
1464 return EFI_SUCCESS;
1467 EFI_STATUS
1468 IsaSerialFifoRemove (
1469 IN SERIAL_DEV_FIFO *Fifo,
1470 OUT UINT8 *Data
1472 /*++
1474 Routine Description:
1475 Remove data from specific FIFO
1477 Arguments:
1478 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1479 Data UINT8*: the data removed from FIFO
1481 Returns:
1482 EFI_SUCCESS: Remove data from specific FIFO successfully
1483 EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty
1485 --*/
1486 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1489 // if FIFO is empty, no data can remove
1491 if (IsaSerialFifoEmpty (Fifo)) {
1492 return EFI_OUT_OF_RESOURCES;
1496 // FIFO is not empty, can remove data
1498 *Data = Fifo->Data[Fifo->First];
1499 Fifo->Surplus++;
1500 Fifo->First++;
1501 if (Fifo->First >= SERIAL_MAX_BUFFER_SIZE) {
1502 Fifo->First = 0;
1505 return EFI_SUCCESS;