]> git.proxmox.com Git - mirror_edk2.git/blob - EdkNt32Pkg/Dxe/WinNtThunk/Bus/SerialIo/WinNtSerialIo.c
1. Perfect libraries MSA files
[mirror_edk2.git] / EdkNt32Pkg / Dxe / WinNtThunk / Bus / SerialIo / WinNtSerialIo.c
1 /*++
2
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
8
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.
11
12 Module Name:
13
14 WinNtSerialIo.c
15
16 Abstract:
17
18 Our DriverBinding member functions operate on the handles
19 created by the NT Bus driver.
20
21 Handle(1) - WinNtIo - DevicePath(1)
22
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.
26
27 Handle(2) - SerialIo - DevicePath(1)\UART
28
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).
32
33 Handle(1) - WinNtIo - DevicePath(1) - WinNtSerialPort
34
35 If the driver is unloaded Handle(2) is removed from the system and
36 gEfiWinNtSerialPortGuid is removed from Handle(1).
37
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.
42
43 If Handle(1) contains a gEfiWinNtSerialPortGuid protocol then the driver is
44 loaded on the device.
45
46 --*/
47
48 #include "WinNtSerialIo.h"
49
50 EFI_DRIVER_BINDING_PROTOCOL gWinNtSerialIoDriverBinding = {
51 WinNtSerialIoDriverBindingSupported,
52 WinNtSerialIoDriverBindingStart,
53 WinNtSerialIoDriverBindingStop,
54 0xa,
55 NULL,
56 NULL
57 };
58
59 STATIC
60 EFI_STATUS
61 EFIAPI
62 WinNtSerialIoDriverBindingSupported (
63 IN EFI_DRIVER_BINDING_PROTOCOL *This,
64 IN EFI_HANDLE Handle,
65 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
66 )
67 /*++
68
69 Routine Description:
70
71 Arguments:
72
73 Returns:
74
75 None
76
77 --*/
78 // TODO: This - add argument and description to function comment
79 // TODO: Handle - add argument and description to function comment
80 // TODO: RemainingDevicePath - add argument and description to function comment
81 // TODO: EFI_SUCCESS - add return value to function comment
82 // TODO: EFI_SUCCESS - add return value to function comment
83 {
84 EFI_STATUS Status;
85 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
86 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
87 UART_DEVICE_PATH *UartNode;
88
89 //
90 // Open the IO Abstraction(s) needed to perform the supported test
91 //
92 Status = gBS->OpenProtocol (
93 Handle,
94 &gEfiDevicePathProtocolGuid,
95 &ParentDevicePath,
96 This->DriverBindingHandle,
97 Handle,
98 EFI_OPEN_PROTOCOL_BY_DRIVER
99 );
100 if (Status == EFI_ALREADY_STARTED) {
101 return EFI_SUCCESS;
102 }
103
104 if (EFI_ERROR (Status)) {
105 return Status;
106 }
107
108 gBS->CloseProtocol (
109 Handle,
110 &gEfiDevicePathProtocolGuid,
111 This->DriverBindingHandle,
112 Handle
113 );
114
115 Status = gBS->OpenProtocol (
116 Handle,
117 &gEfiWinNtIoProtocolGuid,
118 &WinNtIo,
119 This->DriverBindingHandle,
120 Handle,
121 EFI_OPEN_PROTOCOL_BY_DRIVER
122 );
123 if (Status == EFI_ALREADY_STARTED) {
124 return EFI_SUCCESS;
125 }
126
127 if (EFI_ERROR (Status)) {
128 return Status;
129 }
130
131 //
132 // Make sure that the WinNt Thunk Protocol is valid
133 //
134 if (WinNtIo->WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
135 Status = EFI_UNSUPPORTED;
136 goto Error;
137 }
138
139 //
140 // Check the GUID to see if this is a handle type the driver supports
141 //
142 if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtSerialPortGuid)) {
143 Status = EFI_UNSUPPORTED;
144 goto Error;
145 }
146
147 if (RemainingDevicePath != NULL) {
148 Status = EFI_UNSUPPORTED;
149 UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
150 if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
151 UartNode->Header.SubType != MSG_UART_DP ||
152 DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) {
153 goto Error;
154 }
155 if (UartNode->BaudRate < 0 || UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
156 goto Error;
157 }
158 if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
159 goto Error;
160 }
161 if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
162 goto Error;
163 }
164 if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
165 goto Error;
166 }
167 if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
168 goto Error;
169 }
170 if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
171 goto Error;
172 }
173 Status = EFI_SUCCESS;
174 }
175
176 Error:
177 //
178 // Close the I/O Abstraction(s) used to perform the supported test
179 //
180 gBS->CloseProtocol (
181 Handle,
182 &gEfiWinNtIoProtocolGuid,
183 This->DriverBindingHandle,
184 Handle
185 );
186
187 return Status;
188 }
189
190 STATIC
191 EFI_STATUS
192 EFIAPI
193 WinNtSerialIoDriverBindingStart (
194 IN EFI_DRIVER_BINDING_PROTOCOL *This,
195 IN EFI_HANDLE Handle,
196 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
197 )
198 /*++
199
200 Routine Description:
201
202 Arguments:
203
204 Returns:
205
206 None
207
208 --*/
209 // TODO: This - add argument and description to function comment
210 // TODO: Handle - add argument and description to function comment
211 // TODO: RemainingDevicePath - add argument and description to function comment
212 // TODO: EFI_SUCCESS - add return value to function comment
213 // TODO: EFI_SUCCESS - add return value to function comment
214 {
215 EFI_STATUS Status;
216 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
217 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
218 HANDLE NtHandle;
219 UART_DEVICE_PATH Node;
220 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
221 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
222 UINTN EntryCount;
223 UINTN Index;
224 EFI_SERIAL_IO_PROTOCOL *SerialIo;
225
226 Private = NULL;
227 NtHandle = INVALID_HANDLE_VALUE;
228
229 //
230 // Grab the protocols we need
231 //
232 Status = gBS->OpenProtocol (
233 Handle,
234 &gEfiDevicePathProtocolGuid,
235 &ParentDevicePath,
236 This->DriverBindingHandle,
237 Handle,
238 EFI_OPEN_PROTOCOL_BY_DRIVER
239 );
240 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
241 return Status;
242 }
243
244 //
245 // Grab the IO abstraction we need to get any work done
246 //
247 Status = gBS->OpenProtocol (
248 Handle,
249 &gEfiWinNtIoProtocolGuid,
250 &WinNtIo,
251 This->DriverBindingHandle,
252 Handle,
253 EFI_OPEN_PROTOCOL_BY_DRIVER
254 );
255 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
256 gBS->CloseProtocol (
257 Handle,
258 &gEfiDevicePathProtocolGuid,
259 This->DriverBindingHandle,
260 Handle
261 );
262 return Status;
263 }
264
265 if (Status == EFI_ALREADY_STARTED) {
266
267 if (RemainingDevicePath == NULL) {
268 return EFI_SUCCESS;
269 }
270
271 //
272 // Make sure a child handle does not already exist. This driver can only
273 // produce one child per serial port.
274 //
275 Status = gBS->OpenProtocolInformation (
276 Handle,
277 &gEfiWinNtIoProtocolGuid,
278 &OpenInfoBuffer,
279 &EntryCount
280 );
281 if (EFI_ERROR (Status)) {
282 return Status;
283 }
284
285 Status = EFI_ALREADY_STARTED;
286 for (Index = 0; Index < EntryCount; Index++) {
287 if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
288 Status = gBS->OpenProtocol (
289 OpenInfoBuffer[Index].ControllerHandle,
290 &gEfiSerialIoProtocolGuid,
291 &SerialIo,
292 This->DriverBindingHandle,
293 Handle,
294 EFI_OPEN_PROTOCOL_GET_PROTOCOL
295 );
296 if (!EFI_ERROR (Status)) {
297 CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
298 Status = SerialIo->SetAttributes (
299 SerialIo,
300 Node.BaudRate,
301 SerialIo->Mode->ReceiveFifoDepth,
302 SerialIo->Mode->Timeout,
303 Node.Parity,
304 Node.DataBits,
305 Node.StopBits
306 );
307 }
308 break;
309 }
310 }
311
312 FreePool (OpenInfoBuffer);
313 return Status;
314 }
315
316 //
317 // Check to see if we can access the hardware device. If it's Open in NT we
318 // will not get access.
319 //
320 NtHandle = WinNtIo->WinNtThunk->CreateFile (
321 WinNtIo->EnvString,
322 GENERIC_READ | GENERIC_WRITE,
323 0,
324 NULL,
325 OPEN_EXISTING,
326 0,
327 NULL
328 );
329 if (NtHandle == INVALID_HANDLE_VALUE) {
330 Status = EFI_DEVICE_ERROR;
331 goto Error;
332 }
333
334 //
335 // Construct Private data
336 //
337 Private = AllocatePool (sizeof (WIN_NT_SERIAL_IO_PRIVATE_DATA));
338 if (Private == NULL) {
339 goto Error;
340 }
341
342 //
343 // This signature must be valid before any member function is called
344 //
345 Private->Signature = WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
346 Private->NtHandle = NtHandle;
347 Private->ControllerHandle = Handle;
348 Private->Handle = NULL;
349 Private->WinNtThunk = WinNtIo->WinNtThunk;
350 Private->ParentDevicePath = ParentDevicePath;
351 Private->ControllerNameTable = NULL;
352
353 Private->SoftwareLoopbackEnable = FALSE;
354 Private->HardwareLoopbackEnable = FALSE;
355 Private->HardwareFlowControl = FALSE;
356 Private->Fifo.First = 0;
357 Private->Fifo.Last = 0;
358 Private->Fifo.Surplus = SERIAL_MAX_BUFFER_SIZE;
359
360 AddUnicodeString (
361 "eng",
362 gWinNtSerialIoComponentName.SupportedLanguages,
363 &Private->ControllerNameTable,
364 WinNtIo->EnvString
365 );
366
367 Private->SerialIo.Revision = SERIAL_IO_INTERFACE_REVISION;
368 Private->SerialIo.Reset = WinNtSerialIoReset;
369 Private->SerialIo.SetAttributes = WinNtSerialIoSetAttributes;
370 Private->SerialIo.SetControl = WinNtSerialIoSetControl;
371 Private->SerialIo.GetControl = WinNtSerialIoGetControl;
372 Private->SerialIo.Write = WinNtSerialIoWrite;
373 Private->SerialIo.Read = WinNtSerialIoRead;
374 Private->SerialIo.Mode = &Private->SerialIoMode;
375
376 if (RemainingDevicePath != NULL) {
377 //
378 // Match the configuration of the RemainingDevicePath. IsHandleSupported()
379 // already checked to make sure the RemainingDevicePath contains settings
380 // that we can support.
381 //
382 CopyMem (&Private->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
383 } else {
384 //
385 // Build the device path by appending the UART node to the ParentDevicePath
386 // from the WinNtIo handle. The Uart setings are zero here, since
387 // SetAttribute() will update them to match the default setings.
388 //
389 ZeroMem (&Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
390 Private->UartDevicePath.Header.Type = MESSAGING_DEVICE_PATH;
391 Private->UartDevicePath.Header.SubType = MSG_UART_DP;
392 SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
393 }
394
395 //
396 // Build the device path by appending the UART node to the ParentDevicePath
397 // from the WinNtIo handle. The Uart setings are zero here, since
398 // SetAttribute() will update them to match the current setings.
399 //
400 Private->DevicePath = AppendDevicePathNode (
401 ParentDevicePath,
402 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
403 );
404 if (Private->DevicePath == NULL) {
405 Status = EFI_OUT_OF_RESOURCES;
406 goto Error;
407 }
408
409 //
410 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
411 //
412 Private->SerialIoMode.ControlMask = SERIAL_CONTROL_MASK;
413 Private->SerialIoMode.Timeout = SERIAL_TIMEOUT_DEFAULT;
414 Private->SerialIoMode.BaudRate = Private->UartDevicePath.BaudRate;
415 Private->SerialIoMode.ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
416 Private->SerialIoMode.DataBits = Private->UartDevicePath.DataBits;
417 Private->SerialIoMode.Parity = Private->UartDevicePath.Parity;
418 Private->SerialIoMode.StopBits = Private->UartDevicePath.StopBits;
419
420 //
421 // Issue a reset to initialize the COM port
422 //
423 Status = Private->SerialIo.Reset (&Private->SerialIo);
424 if (EFI_ERROR (Status)) {
425 goto Error;
426 }
427
428 //
429 // Create new child handle
430 //
431 Status = gBS->InstallMultipleProtocolInterfaces (
432 &Private->Handle,
433 &gEfiSerialIoProtocolGuid,
434 &Private->SerialIo,
435 &gEfiDevicePathProtocolGuid,
436 Private->DevicePath,
437 NULL
438 );
439 if (EFI_ERROR (Status)) {
440 goto Error;
441 }
442
443 //
444 // Open For Child Device
445 //
446 Status = gBS->OpenProtocol (
447 Handle,
448 &gEfiWinNtIoProtocolGuid,
449 &WinNtIo,
450 This->DriverBindingHandle,
451 Private->Handle,
452 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
453 );
454 if (EFI_ERROR (Status)) {
455 goto Error;
456 }
457
458 return EFI_SUCCESS;
459
460 Error:
461 //
462 // Use the Stop() function to free all resources allocated in Start()
463 //
464 if (Private != NULL) {
465 if (Private->Handle != NULL) {
466 This->Stop (This, Handle, 1, &Private->Handle);
467 } else {
468 if (NtHandle != INVALID_HANDLE_VALUE) {
469 Private->WinNtThunk->CloseHandle (NtHandle);
470 }
471
472 if (Private->DevicePath != NULL) {
473 FreePool (Private->DevicePath);
474 }
475
476 FreeUnicodeStringTable (Private->ControllerNameTable);
477
478 FreePool (Private);
479 }
480 }
481
482 This->Stop (This, Handle, 0, NULL);
483
484 return Status;
485 }
486
487 STATIC
488 EFI_STATUS
489 EFIAPI
490 WinNtSerialIoDriverBindingStop (
491 IN EFI_DRIVER_BINDING_PROTOCOL *This,
492 IN EFI_HANDLE Handle,
493 IN UINTN NumberOfChildren,
494 IN EFI_HANDLE *ChildHandleBuffer
495 )
496 /*++
497
498 Routine Description:
499
500 TODO: Add function description
501
502 Arguments:
503
504 This - TODO: add argument description
505 Handle - TODO: add argument description
506 NumberOfChildren - TODO: add argument description
507 ChildHandleBuffer - TODO: add argument description
508
509 Returns:
510
511 EFI_DEVICE_ERROR - TODO: Add description for return value
512 EFI_SUCCESS - TODO: Add description for return value
513
514 --*/
515 {
516 EFI_STATUS Status;
517 UINTN Index;
518 BOOLEAN AllChildrenStopped;
519 EFI_SERIAL_IO_PROTOCOL *SerialIo;
520 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
521 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
522
523 //
524 // Complete all outstanding transactions to Controller.
525 // Don't allow any new transaction to Controller to be started.
526 //
527
528 if (NumberOfChildren == 0) {
529 //
530 // Close the bus driver
531 //
532 Status = gBS->CloseProtocol (
533 Handle,
534 &gEfiWinNtIoProtocolGuid,
535 This->DriverBindingHandle,
536 Handle
537 );
538 Status = gBS->CloseProtocol (
539 Handle,
540 &gEfiDevicePathProtocolGuid,
541 This->DriverBindingHandle,
542 Handle
543 );
544 return Status;
545 }
546
547 AllChildrenStopped = TRUE;
548
549 for (Index = 0; Index < NumberOfChildren; Index++) {
550 Status = gBS->OpenProtocol (
551 ChildHandleBuffer[Index],
552 &gEfiSerialIoProtocolGuid,
553 &SerialIo,
554 This->DriverBindingHandle,
555 Handle,
556 EFI_OPEN_PROTOCOL_GET_PROTOCOL
557 );
558 if (!EFI_ERROR (Status)) {
559 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo);
560
561 ASSERT (Private->Handle == ChildHandleBuffer[Index]);
562
563 Status = gBS->CloseProtocol (
564 Handle,
565 &gEfiWinNtIoProtocolGuid,
566 This->DriverBindingHandle,
567 ChildHandleBuffer[Index]
568 );
569
570 Status = gBS->UninstallMultipleProtocolInterfaces (
571 ChildHandleBuffer[Index],
572 &gEfiSerialIoProtocolGuid,
573 &Private->SerialIo,
574 &gEfiDevicePathProtocolGuid,
575 Private->DevicePath,
576 NULL
577 );
578
579 if (EFI_ERROR (Status)) {
580 gBS->OpenProtocol (
581 Handle,
582 &gEfiWinNtIoProtocolGuid,
583 (VOID **) &WinNtIo,
584 This->DriverBindingHandle,
585 ChildHandleBuffer[Index],
586 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
587 );
588 } else {
589 Private->WinNtThunk->CloseHandle (Private->NtHandle);
590
591 FreePool (Private->DevicePath);
592
593 FreeUnicodeStringTable (Private->ControllerNameTable);
594
595 FreePool (Private);
596 }
597 }
598
599 if (EFI_ERROR (Status)) {
600 AllChildrenStopped = FALSE;
601 }
602 }
603
604 if (!AllChildrenStopped) {
605 return EFI_DEVICE_ERROR;
606 }
607
608 return EFI_SUCCESS;
609 }
610
611 //
612 // Serial IO Protocol member functions
613 //
614
615 STATIC
616 EFI_STATUS
617 EFIAPI
618 WinNtSerialIoReset (
619 IN EFI_SERIAL_IO_PROTOCOL *This
620 )
621 /*++
622
623 Routine Description:
624
625 TODO: Add function description
626
627 Arguments:
628
629 This - TODO: add argument description
630
631 Returns:
632
633 TODO: add return values
634
635 --*/
636 {
637 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
638 EFI_TPL Tpl;
639
640 Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
641
642 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
643
644 Private->WinNtThunk->PurgeComm (
645 Private->NtHandle,
646 PURGE_TXCLEAR | PURGE_RXCLEAR
647 );
648
649 gBS->RestoreTPL (Tpl);
650
651 return This->SetAttributes (
652 This,
653 This->Mode->BaudRate,
654 This->Mode->ReceiveFifoDepth,
655 This->Mode->Timeout,
656 This->Mode->Parity,
657 (UINT8) This->Mode->DataBits,
658 This->Mode->StopBits
659 );
660 }
661
662 STATIC
663 EFI_STATUS
664 EFIAPI
665 WinNtSerialIoSetAttributes (
666 IN EFI_SERIAL_IO_PROTOCOL *This,
667 IN UINT64 BaudRate,
668 IN UINT32 ReceiveFifoDepth,
669 IN UINT32 Timeout,
670 IN EFI_PARITY_TYPE Parity,
671 IN UINT8 DataBits,
672 IN EFI_STOP_BITS_TYPE StopBits
673 )
674 /*++
675
676 Routine Description:
677
678 This function is used to set the attributes.
679
680 Arguments:
681
682 This - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue.
683 BaudRate - The Baud rate of the serial device.
684 ReceiveFifoDepth - The request depth of fifo on receive side.
685 Timeout - the request timeout for a single charact.
686 Parity - The type of parity used in serial device.
687 DataBits - Number of deata bits used in serial device.
688 StopBits - Number of stop bits used in serial device.
689
690 Returns:
691 Status code
692
693 None
694
695 --*/
696 // TODO: EFI_SUCCESS - add return value to function comment
697 // TODO: EFI_DEVICE_ERROR - add return value to function comment
698 // TODO: EFI_DEVICE_ERROR - add return value to function comment
699 // TODO: EFI_DEVICE_ERROR - add return value to function comment
700 // TODO: EFI_SUCCESS - add return value to function comment
701 // TODO: EFI_DEVICE_ERROR - add return value to function comment
702 // TODO: EFI_SUCCESS - add return value to function comment
703 {
704 EFI_STATUS Status;
705 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
706 COMMTIMEOUTS PortTimeOuts;
707 DWORD ConvertedTime;
708 BOOL Result;
709 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
710 EFI_TPL Tpl;
711
712 Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
713
714 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
715
716 //
717 // Some of our arguments have defaults if a null value is passed in, and
718 // we must set the default values if a null argument is passed in.
719 //
720 if (BaudRate == 0) {
721 BaudRate = SERIAL_BAUD_DEFAULT;
722 }
723
724 if (ReceiveFifoDepth == 0) {
725 ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
726 }
727
728 if (Timeout == 0) {
729 Timeout = SERIAL_TIMEOUT_DEFAULT;
730 }
731
732 if (Parity == DefaultParity) {
733 Parity = NoParity;
734 }
735
736 if (DataBits == 0) {
737 DataBits = SERIAL_DATABITS_DEFAULT;
738 }
739
740 if (StopBits == DefaultStopBits) {
741 StopBits = OneStopBit;
742 }
743 //
744 // See if the new attributes already match the current attributes
745 //
746 if (Private->UartDevicePath.BaudRate == BaudRate &&
747 Private->UartDevicePath.DataBits == DataBits &&
748 Private->UartDevicePath.Parity == Parity &&
749 Private->UartDevicePath.StopBits == StopBits &&
750 Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth &&
751 Private->SerialIoMode.Timeout == Timeout ) {
752 gBS->RestoreTPL(Tpl);
753 return EFI_SUCCESS;
754 }
755
756 //
757 // Get current values from NT
758 //
759 ZeroMem (&Private->NtDCB, sizeof (DCB));
760 Private->NtDCB.DCBlength = sizeof (DCB);
761
762 if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Private->NtDCB)) {
763 Private->NtError = Private->WinNtThunk->GetLastError ();
764 DEBUG ((EFI_D_ERROR, "SerialSetAttributes: GetCommState %d\n", Private->NtError));
765 gBS->RestoreTPL (Tpl);
766 return EFI_DEVICE_ERROR;
767 }
768
769 //
770 // Map EFI com setting to NT
771 //
772 Private->NtDCB.BaudRate = ConvertBaud2Nt (BaudRate);
773 Private->NtDCB.ByteSize = ConvertData2Nt (DataBits);
774 Private->NtDCB.Parity = ConvertParity2Nt (Parity);
775 Private->NtDCB.StopBits = ConvertStop2Nt (StopBits);
776
777 Private->NtDCB.fBinary = TRUE;
778 Private->NtDCB.fParity = Private->NtDCB.Parity == NOPARITY ? FALSE : TRUE;
779 Private->NtDCB.fOutxCtsFlow = FALSE;
780 Private->NtDCB.fOutxDsrFlow = FALSE;
781 Private->NtDCB.fDtrControl = DTR_CONTROL_ENABLE;
782 Private->NtDCB.fDsrSensitivity = FALSE;
783 Private->NtDCB.fOutX = FALSE;
784 Private->NtDCB.fInX = FALSE;
785 Private->NtDCB.fRtsControl = RTS_CONTROL_ENABLE;
786 Private->NtDCB.fNull = FALSE;
787
788 //
789 // Set new values
790 //
791 Result = Private->WinNtThunk->SetCommState (Private->NtHandle, &Private->NtDCB);
792 if (!Result) {
793 Private->NtError = Private->WinNtThunk->GetLastError ();
794 DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommState %d\n", Private->NtError));
795 gBS->RestoreTPL (Tpl);
796 return EFI_DEVICE_ERROR;
797 }
798
799 //
800 // Set com port read/write timeout values
801 //
802 ConvertedTime = ConvertTime2Nt (Timeout);
803 PortTimeOuts.ReadIntervalTimeout = MAXDWORD;
804 PortTimeOuts.ReadTotalTimeoutMultiplier = 0;
805 PortTimeOuts.ReadTotalTimeoutConstant = ConvertedTime;
806 PortTimeOuts.WriteTotalTimeoutMultiplier = ConvertedTime == 0 ? 1 : ConvertedTime;
807 PortTimeOuts.WriteTotalTimeoutConstant = 0;
808
809 if (!Private->WinNtThunk->SetCommTimeouts (Private->NtHandle, &PortTimeOuts)) {
810 Private->NtError = Private->WinNtThunk->GetLastError ();
811 DEBUG ((EFI_D_ERROR, "SerialSetAttributes: SetCommTimeouts %d\n", Private->NtError));
812 gBS->RestoreTPL (Tpl);
813 return EFI_DEVICE_ERROR;
814 }
815
816 //
817 // Update mode
818 //
819 Private->SerialIoMode.BaudRate = BaudRate;
820 Private->SerialIoMode.ReceiveFifoDepth = ReceiveFifoDepth;
821 Private->SerialIoMode.Timeout = Timeout;
822 Private->SerialIoMode.Parity = Parity;
823 Private->SerialIoMode.DataBits = DataBits;
824 Private->SerialIoMode.StopBits = StopBits;
825
826 //
827 // See if Device Path Node has actually changed
828 //
829 if (Private->UartDevicePath.BaudRate == BaudRate &&
830 Private->UartDevicePath.DataBits == DataBits &&
831 Private->UartDevicePath.Parity == Parity &&
832 Private->UartDevicePath.StopBits == StopBits ) {
833 gBS->RestoreTPL(Tpl);
834 return EFI_SUCCESS;
835 }
836
837 //
838 // Update the device path
839 //
840 Private->UartDevicePath.BaudRate = BaudRate;
841 Private->UartDevicePath.DataBits = DataBits;
842 Private->UartDevicePath.Parity = (UINT8) Parity;
843 Private->UartDevicePath.StopBits = (UINT8) StopBits;
844
845 NewDevicePath = AppendDevicePathNode (
846 Private->ParentDevicePath,
847 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
848 );
849 if (NewDevicePath == NULL) {
850 gBS->RestoreTPL (Tpl);
851 return EFI_DEVICE_ERROR;
852 }
853
854 if (Private->Handle != NULL) {
855 Status = gBS->ReinstallProtocolInterface (
856 Private->Handle,
857 &gEfiDevicePathProtocolGuid,
858 Private->DevicePath,
859 NewDevicePath
860 );
861 if (EFI_ERROR (Status)) {
862 gBS->RestoreTPL (Tpl);
863 return Status;
864 }
865 }
866
867 if (Private->DevicePath != NULL) {
868 FreePool (Private->DevicePath);
869 }
870
871 Private->DevicePath = NewDevicePath;
872
873 gBS->RestoreTPL (Tpl);
874
875 return EFI_SUCCESS;
876 }
877
878 STATIC
879 EFI_STATUS
880 EFIAPI
881 WinNtSerialIoSetControl (
882 IN EFI_SERIAL_IO_PROTOCOL *This,
883 IN UINT32 Control
884 )
885 /*++
886
887 Routine Description:
888
889 TODO: Add function description
890
891 Arguments:
892
893 This - TODO: add argument description
894 Control - TODO: add argument description
895
896 Returns:
897
898 EFI_DEVICE_ERROR - TODO: Add description for return value
899 EFI_DEVICE_ERROR - TODO: Add description for return value
900 EFI_SUCCESS - TODO: Add description for return value
901
902 --*/
903 {
904 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
905 BOOL Result;
906 DCB Dcb;
907 EFI_TPL Tpl;
908
909 Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
910
911 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
912
913 Result = Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb);
914
915 if (!Result) {
916 Private->NtError = Private->WinNtThunk->GetLastError ();
917 DEBUG ((EFI_D_ERROR, "SerialSetControl: GetCommState %d\n", Private->NtError));
918 gBS->RestoreTPL (Tpl);
919 return EFI_DEVICE_ERROR;
920 }
921
922 Dcb.fRtsControl = RTS_CONTROL_DISABLE;
923 Dcb.fDtrControl = DTR_CONTROL_DISABLE;
924 Private->HardwareFlowControl = FALSE;
925 Private->SoftwareLoopbackEnable = FALSE;
926 Private->HardwareLoopbackEnable = FALSE;
927
928 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
929 Dcb.fRtsControl = RTS_CONTROL_ENABLE;
930 }
931
932 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
933 Dcb.fDtrControl = DTR_CONTROL_ENABLE;
934 }
935
936 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
937 Private->HardwareFlowControl = TRUE;
938 }
939
940 if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
941 Private->SoftwareLoopbackEnable = TRUE;
942 }
943
944 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
945 Private->HardwareLoopbackEnable = TRUE;
946 }
947
948 Result = Private->WinNtThunk->SetCommState (
949 Private->NtHandle,
950 &Dcb
951 );
952
953 if (!Result) {
954 Private->NtError = Private->WinNtThunk->GetLastError ();
955 DEBUG ((EFI_D_ERROR, "SerialSetControl: SetCommState %d\n", Private->NtError));
956 gBS->RestoreTPL (Tpl);
957 return EFI_DEVICE_ERROR;
958 }
959
960 gBS->RestoreTPL (Tpl);
961
962 return EFI_SUCCESS;
963 }
964
965 STATIC
966 EFI_STATUS
967 EFIAPI
968 WinNtSerialIoGetControl (
969 IN EFI_SERIAL_IO_PROTOCOL *This,
970 OUT UINT32 *Control
971 )
972 /*++
973
974 Routine Description:
975
976 TODO: Add function description
977
978 Arguments:
979
980 This - TODO: add argument description
981 Control - TODO: add argument description
982
983 Returns:
984
985 EFI_DEVICE_ERROR - TODO: Add description for return value
986 EFI_DEVICE_ERROR - TODO: Add description for return value
987 EFI_DEVICE_ERROR - TODO: Add description for return value
988 EFI_SUCCESS - TODO: Add description for return value
989
990 --*/
991 {
992 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
993 DWORD ModemStatus;
994 DWORD Errors;
995 UINT32 Bits;
996 DCB Dcb;
997 EFI_TPL Tpl;
998
999 Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
1000
1001 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1002
1003 //
1004 // Get modem status
1005 //
1006 if (!Private->WinNtThunk->GetCommModemStatus (Private->NtHandle, &ModemStatus)) {
1007 Private->NtError = Private->WinNtThunk->GetLastError ();
1008 gBS->RestoreTPL (Tpl);
1009 return EFI_DEVICE_ERROR;
1010 }
1011
1012 Bits = 0;
1013 if (ModemStatus & MS_CTS_ON) {
1014 Bits |= EFI_SERIAL_CLEAR_TO_SEND;
1015 }
1016
1017 if (ModemStatus & MS_DSR_ON) {
1018 Bits |= EFI_SERIAL_DATA_SET_READY;
1019 }
1020
1021 if (ModemStatus & MS_RING_ON) {
1022 Bits |= EFI_SERIAL_RING_INDICATE;
1023 }
1024
1025 if (ModemStatus & MS_RLSD_ON) {
1026 Bits |= EFI_SERIAL_CARRIER_DETECT;
1027 }
1028
1029 //
1030 // Get ctrl status
1031 //
1032 if (!Private->WinNtThunk->GetCommState (Private->NtHandle, &Dcb)) {
1033 Private->NtError = Private->WinNtThunk->GetLastError ();
1034 DEBUG ((EFI_D_ERROR, "SerialGetControl: GetCommState %d\n", Private->NtError));
1035 gBS->RestoreTPL (Tpl);
1036 return EFI_DEVICE_ERROR;
1037 }
1038
1039 if (Dcb.fDtrControl == DTR_CONTROL_ENABLE) {
1040 Bits |= EFI_SERIAL_DATA_TERMINAL_READY;
1041 }
1042
1043 if (Dcb.fRtsControl == RTS_CONTROL_ENABLE) {
1044 Bits |= EFI_SERIAL_REQUEST_TO_SEND;
1045 }
1046
1047 if (Private->HardwareFlowControl) {
1048 Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1049 }
1050
1051 if (Private->SoftwareLoopbackEnable) {
1052 Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1053 }
1054
1055 if (Private->HardwareLoopbackEnable) {
1056 Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1057 }
1058
1059 //
1060 // Get input buffer status
1061 //
1062 if (!Private->WinNtThunk->ClearCommError (Private->NtHandle, &Errors, &Private->NtComStatus)) {
1063 Private->NtError = Private->WinNtThunk->GetLastError ();
1064 DEBUG ((EFI_D_ERROR, "SerialGetControl: ClearCommError %d\n", Private->NtError));
1065 gBS->RestoreTPL (Tpl);
1066 return EFI_DEVICE_ERROR;
1067 }
1068
1069 if (Private->NtComStatus.cbInQue == 0) {
1070 Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1071 }
1072
1073 *Control = Bits;
1074
1075 gBS->RestoreTPL (Tpl);
1076
1077 return EFI_SUCCESS;
1078 }
1079
1080 STATIC
1081 EFI_STATUS
1082 EFIAPI
1083 WinNtSerialIoWrite (
1084 IN EFI_SERIAL_IO_PROTOCOL *This,
1085 IN OUT UINTN *BufferSize,
1086 IN VOID *Buffer
1087 )
1088 /*++
1089
1090 Routine Description:
1091
1092 TODO: Add function description
1093
1094 Arguments:
1095
1096 This - TODO: add argument description
1097 BufferSize - TODO: add argument description
1098 Buffer - TODO: add argument description
1099
1100 Returns:
1101
1102 EFI_DEVICE_ERROR - TODO: Add description for return value
1103 EFI_SUCCESS - TODO: Add description for return value
1104
1105 --*/
1106 {
1107 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1108 UINT8 *ByteBuffer;
1109 UINTN TotalBytesWritten;
1110 DWORD BytesToGo;
1111 DWORD BytesWritten;
1112 BOOL Result;
1113 UINT32 Index;
1114 UINT32 Control;
1115 EFI_TPL Tpl;
1116
1117 Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
1118
1119 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1120
1121 ByteBuffer = (UINT8 *) Buffer;
1122 TotalBytesWritten = 0;
1123
1124 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1125 for (Index = 0; Index < *BufferSize; Index++) {
1126 if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) {
1127 TotalBytesWritten++;
1128 } else {
1129 break;
1130 }
1131 }
1132 } else {
1133 BytesToGo = (DWORD) (*BufferSize);
1134
1135 do {
1136 if (Private->HardwareFlowControl) {
1137 //
1138 // Send RTS
1139 //
1140 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1141 Control |= EFI_SERIAL_REQUEST_TO_SEND;
1142 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1143 }
1144
1145 //
1146 // Do the write
1147 //
1148 Result = Private->WinNtThunk->WriteFile (
1149 Private->NtHandle,
1150 &ByteBuffer[TotalBytesWritten],
1151 BytesToGo,
1152 &BytesWritten,
1153 NULL
1154 );
1155
1156 if (Private->HardwareFlowControl) {
1157 //
1158 // Assert RTS
1159 //
1160 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1161 Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND;
1162 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1163 }
1164
1165 TotalBytesWritten += BytesWritten;
1166 BytesToGo -= BytesWritten;
1167 if (!Result) {
1168 Private->NtError = Private->WinNtThunk->GetLastError ();
1169 DEBUG ((EFI_D_ERROR, "SerialWrite: FileWrite %d\n", Private->NtError));
1170 *BufferSize = TotalBytesWritten;
1171 gBS->RestoreTPL (Tpl);
1172 return EFI_DEVICE_ERROR;
1173 }
1174 } while (BytesToGo > 0);
1175 }
1176
1177 *BufferSize = TotalBytesWritten;
1178
1179 gBS->RestoreTPL (Tpl);
1180
1181 return EFI_SUCCESS;
1182 }
1183
1184 STATIC
1185 EFI_STATUS
1186 EFIAPI
1187 WinNtSerialIoRead (
1188 IN EFI_SERIAL_IO_PROTOCOL *This,
1189 IN OUT UINTN *BufferSize,
1190 OUT VOID *Buffer
1191 )
1192 /*++
1193
1194 Routine Description:
1195
1196 TODO: Add function description
1197
1198 Arguments:
1199
1200 This - TODO: add argument description
1201 BufferSize - TODO: add argument description
1202 Buffer - TODO: add argument description
1203
1204 Returns:
1205
1206 EFI_DEVICE_ERROR - TODO: Add description for return value
1207
1208 --*/
1209 {
1210 WIN_NT_SERIAL_IO_PRIVATE_DATA *Private;
1211 BOOL Result;
1212 DWORD BytesRead;
1213 EFI_STATUS Status;
1214 UINT32 Index;
1215 UINT8 Data;
1216 UINT32 Control;
1217 EFI_TPL Tpl;
1218
1219 Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
1220
1221 Private = WIN_NT_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1222
1223 //
1224 // Do the read
1225 //
1226 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1227 for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) {
1228 if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) {
1229 ((UINT8 *) Buffer)[Index] = Data;
1230 BytesRead++;
1231 } else {
1232 break;
1233 }
1234 }
1235 } else {
1236 if (Private->HardwareFlowControl) {
1237 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1238 Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1239 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1240 }
1241
1242 Result = Private->WinNtThunk->ReadFile (
1243 Private->NtHandle,
1244 Buffer,
1245 (DWORD) *BufferSize,
1246 &BytesRead,
1247 NULL
1248 );
1249
1250 if (Private->HardwareFlowControl) {
1251 WinNtSerialIoGetControl (&Private->SerialIo, &Control);
1252 Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY;
1253 WinNtSerialIoSetControl (&Private->SerialIo, Control);
1254 }
1255
1256 if (!Result) {
1257 Private->NtError = Private->WinNtThunk->GetLastError ();
1258 gBS->RestoreTPL (Tpl);
1259 return EFI_DEVICE_ERROR;
1260 }
1261 }
1262
1263 if (BytesRead != *BufferSize) {
1264 Status = EFI_TIMEOUT;
1265 } else {
1266 Status = EFI_SUCCESS;
1267 }
1268
1269 *BufferSize = (UINTN) BytesRead;
1270
1271 gBS->RestoreTPL (Tpl);
1272
1273 return Status;
1274 }
1275
1276 BOOLEAN
1277 IsaSerialFifoFull (
1278 IN SERIAL_DEV_FIFO *Fifo
1279 )
1280 /*++
1281
1282 Routine Description:
1283 Detect whether specific FIFO is full or not
1284
1285 Arguments:
1286 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1287
1288 Returns:
1289 TRUE: the FIFO is full
1290 FALSE: the FIFO is not full
1291
1292 --*/
1293 {
1294 if (Fifo->Surplus == 0) {
1295 return TRUE;
1296 }
1297
1298 return FALSE;
1299 }
1300
1301 BOOLEAN
1302 IsaSerialFifoEmpty (
1303 IN SERIAL_DEV_FIFO *Fifo
1304 )
1305 /*++
1306
1307 Routine Description:
1308 Detect whether specific FIFO is empty or not
1309
1310 Arguments:
1311 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1312
1313 Returns:
1314 TRUE: the FIFO is empty
1315 FALSE: the FIFO is not empty
1316
1317 --*/
1318 {
1319 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
1320 return TRUE;
1321 }
1322
1323 return FALSE;
1324 }
1325
1326 EFI_STATUS
1327 IsaSerialFifoAdd (
1328 IN SERIAL_DEV_FIFO *Fifo,
1329 IN UINT8 Data
1330 )
1331 /*++
1332
1333 Routine Description:
1334 Add data to specific FIFO
1335
1336 Arguments:
1337 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1338 Data UINT8: the data added to FIFO
1339
1340 Returns:
1341 EFI_SUCCESS: Add data to specific FIFO successfully
1342 EFI_OUT_RESOURCE: Failed to add data because FIFO is already full
1343
1344 --*/
1345 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1346 {
1347 //
1348 // if FIFO full can not add data
1349 //
1350 if (IsaSerialFifoFull (Fifo)) {
1351 return EFI_OUT_OF_RESOURCES;
1352 }
1353
1354 //
1355 // FIFO is not full can add data
1356 //
1357 Fifo->Data[Fifo->Last] = Data;
1358 Fifo->Surplus--;
1359 Fifo->Last++;
1360 if (Fifo->Last >= SERIAL_MAX_BUFFER_SIZE) {
1361 Fifo->Last = 0;
1362 }
1363
1364 return EFI_SUCCESS;
1365 }
1366
1367 EFI_STATUS
1368 IsaSerialFifoRemove (
1369 IN SERIAL_DEV_FIFO *Fifo,
1370 OUT UINT8 *Data
1371 )
1372 /*++
1373
1374 Routine Description:
1375 Remove data from specific FIFO
1376
1377 Arguments:
1378 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1379 Data UINT8*: the data removed from FIFO
1380
1381 Returns:
1382 EFI_SUCCESS: Remove data from specific FIFO successfully
1383 EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty
1384
1385 --*/
1386 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1387 {
1388 //
1389 // if FIFO is empty, no data can remove
1390 //
1391 if (IsaSerialFifoEmpty (Fifo)) {
1392 return EFI_OUT_OF_RESOURCES;
1393 }
1394
1395 //
1396 // FIFO is not empty, can remove data
1397 //
1398 *Data = Fifo->Data[Fifo->First];
1399 Fifo->Surplus++;
1400 Fifo->First++;
1401 if (Fifo->First >= SERIAL_MAX_BUFFER_SIZE) {
1402 Fifo->First = 0;
1403 }
1404
1405 return EFI_SUCCESS;
1406 }