]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c
35b83f96bb4916260b1113057876debb2cec0cac
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaSerialDxe / Serial.c
1 /** @file
2 Serial driver for standard UARTS on an ISA bus.
3
4 Copyright (c) 2006 - 2010, Intel Corporation<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Serial.h"
16
17 //
18 // ISA Serial Driver Global Variables
19 //
20 EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
21 SerialControllerDriverSupported,
22 SerialControllerDriverStart,
23 SerialControllerDriverStop,
24 0xa,
25 NULL,
26 NULL
27 };
28
29
30 SERIAL_DEV gSerialDevTempate = {
31 SERIAL_DEV_SIGNATURE,
32 NULL,
33 { // SerialIo
34 SERIAL_IO_INTERFACE_REVISION,
35 IsaSerialReset,
36 IsaSerialSetAttributes,
37 IsaSerialSetControl,
38 IsaSerialGetControl,
39 IsaSerialWrite,
40 IsaSerialRead,
41 NULL
42 },
43 { // SerialMode
44 SERIAL_PORT_SUPPORT_CONTROL_MASK,
45 SERIAL_PORT_DEFAULT_TIMEOUT,
46 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
47 SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
48 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
49 FixedPcdGet8 (PcdUartDefaultParity), // Parity
50 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
51 },
52 NULL,
53 NULL,
54 { // UartDevicePath
55 {
56 MESSAGING_DEVICE_PATH,
57 MSG_UART_DP,
58 {
59 (UINT8) (sizeof (UART_DEVICE_PATH)),
60 (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
61 }
62 },
63 0,
64 FixedPcdGet64 (PcdUartDefaultBaudRate),
65 FixedPcdGet8 (PcdUartDefaultDataBits),
66 FixedPcdGet8 (PcdUartDefaultParity),
67 FixedPcdGet8 (PcdUartDefaultStopBits)
68 },
69 NULL,
70 0, //BaseAddress
71 {
72 0,
73 0,
74 SERIAL_MAX_BUFFER_SIZE,
75 { 0 }
76 },
77 {
78 0,
79 0,
80 SERIAL_MAX_BUFFER_SIZE,
81 { 0 }
82 },
83 FALSE,
84 FALSE,
85 Uart16550A,
86 NULL
87 };
88
89 /**
90 Check the device path node whether it's the Flow Control node or not.
91
92 @param[in] FlowControl The device path node to be checked.
93
94 @retval TRUE It's the Flow Control node.
95 @retval FALSE It's not.
96
97 **/
98 BOOLEAN
99 IsUartFlowControlNode (
100 IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
101 )
102 {
103 return (BOOLEAN) (
104 (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
105 (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
106 (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
107 );
108 }
109
110 /**
111 Check the device path node whether it contains Flow Control node or not.
112
113 @param[in] DevicePath The device path to be checked.
114
115 @retval TRUE It contains the Flow Control node.
116 @retval FALSE It doesn't.
117
118 **/
119 BOOLEAN
120 ContainsFlowControl (
121 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
122 )
123 {
124 while (!IsDevicePathEnd (DevicePath)) {
125 if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) {
126 return TRUE;
127 }
128 DevicePath = NextDevicePathNode (DevicePath);
129 }
130
131 return FALSE;
132 }
133
134 /**
135 The user Entry Point for module IsaSerial. The user code starts with this function.
136
137 @param[in] ImageHandle The firmware allocated handle for the EFI image.
138 @param[in] SystemTable A pointer to the EFI System Table.
139
140 @retval EFI_SUCCESS The entry point is executed successfully.
141 @retval other Some error occurs when executing this entry point.
142
143 **/
144 EFI_STATUS
145 EFIAPI
146 InitializeIsaSerial (
147 IN EFI_HANDLE ImageHandle,
148 IN EFI_SYSTEM_TABLE *SystemTable
149 )
150 {
151 EFI_STATUS Status;
152
153 //
154 // Install driver model protocol(s).
155 //
156 Status = EfiLibInstallDriverBindingComponentName2 (
157 ImageHandle,
158 SystemTable,
159 &gSerialControllerDriver,
160 ImageHandle,
161 &gIsaSerialComponentName,
162 &gIsaSerialComponentName2
163 );
164 ASSERT_EFI_ERROR (Status);
165
166
167 return Status;
168 }
169
170 /**
171 Check to see if this driver supports the given controller
172
173 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
174 @param Controller The handle of the controller to test.
175 @param RemainingDevicePath A pointer to the remaining portion of a device path.
176
177 @return EFI_SUCCESS This driver can support the given controller
178
179 **/
180 EFI_STATUS
181 EFIAPI
182 SerialControllerDriverSupported (
183 IN EFI_DRIVER_BINDING_PROTOCOL *This,
184 IN EFI_HANDLE Controller,
185 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
186 )
187
188 {
189 EFI_STATUS Status;
190 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
191 EFI_ISA_IO_PROTOCOL *IsaIo;
192 UART_DEVICE_PATH *UartNode;
193 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
194 UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
195 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
196 UINTN EntryCount;
197 UINTN Index;
198 BOOLEAN HasFlowControl;
199
200 //
201 // Check RemainingDevicePath validation
202 //
203 if (RemainingDevicePath != NULL) {
204 //
205 // Check if RemainingDevicePath is the End of Device Path Node,
206 // if yes, go on checking other conditions
207 //
208 if (!IsDevicePathEnd (RemainingDevicePath)) {
209 //
210 // If RemainingDevicePath isn't the End of Device Path Node,
211 // check its validation
212 //
213 Status = EFI_UNSUPPORTED;
214
215 UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
216 if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
217 UartNode->Header.SubType != MSG_UART_DP ||
218 sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) UartNode)
219 ) {
220 goto Error;
221 }
222
223 if (UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
224 goto Error;
225 }
226
227 if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
228 goto Error;
229 }
230
231 if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
232 goto Error;
233 }
234
235 if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
236 goto Error;
237 }
238
239 if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
240 goto Error;
241 }
242
243 if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
244 goto Error;
245 }
246
247 FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);
248 if (IsUartFlowControlNode (FlowControlNode)) {
249 //
250 // If the second node is Flow Control Node,
251 // return error when it request other than hardware flow control.
252 //
253 if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
254 goto Error;
255 }
256 }
257 }
258 }
259
260 //
261 // Open the IO Abstraction(s) needed to perform the supported test
262 //
263 Status = gBS->OpenProtocol (
264 Controller,
265 &gEfiIsaIoProtocolGuid,
266 (VOID **) &IsaIo,
267 This->DriverBindingHandle,
268 Controller,
269 EFI_OPEN_PROTOCOL_BY_DRIVER
270 );
271 if (Status == EFI_ALREADY_STARTED) {
272 if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
273 //
274 // If RemainingDevicePath is NULL or is the End of Device Path Node
275 //
276 return EFI_SUCCESS;
277 }
278 //
279 // When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node,
280 // return unsupported, and vice versa.
281 //
282 Status = gBS->OpenProtocolInformation (
283 Controller,
284 &gEfiIsaIoProtocolGuid,
285 &OpenInfoBuffer,
286 &EntryCount
287 );
288 if (EFI_ERROR (Status)) {
289 return Status;
290 }
291
292 for (Index = 0; Index < EntryCount; Index++) {
293 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
294 Status = gBS->OpenProtocol (
295 OpenInfoBuffer[Index].ControllerHandle,
296 &gEfiDevicePathProtocolGuid,
297 (VOID **) &DevicePath,
298 This->DriverBindingHandle,
299 Controller,
300 EFI_OPEN_PROTOCOL_GET_PROTOCOL
301 );
302 if (!EFI_ERROR (Status)) {
303 HasFlowControl = ContainsFlowControl (RemainingDevicePath);
304 if (HasFlowControl ^ ContainsFlowControl (DevicePath)) {
305 Status = EFI_UNSUPPORTED;
306 }
307 }
308 break;
309 }
310 }
311 FreePool (OpenInfoBuffer);
312 return Status;
313 }
314
315 if (EFI_ERROR (Status)) {
316 return Status;
317 }
318
319 //
320 // Close the I/O Abstraction(s) used to perform the supported test
321 //
322 gBS->CloseProtocol (
323 Controller,
324 &gEfiIsaIoProtocolGuid,
325 This->DriverBindingHandle,
326 Controller
327 );
328
329 //
330 // Open the EFI Device Path protocol needed to perform the supported test
331 //
332 Status = gBS->OpenProtocol (
333 Controller,
334 &gEfiDevicePathProtocolGuid,
335 (VOID **) &ParentDevicePath,
336 This->DriverBindingHandle,
337 Controller,
338 EFI_OPEN_PROTOCOL_BY_DRIVER
339 );
340 if (Status == EFI_ALREADY_STARTED) {
341 return EFI_SUCCESS;
342 }
343
344 if (EFI_ERROR (Status)) {
345 return Status;
346 }
347 //
348 // Use the ISA I/O Protocol to see if Controller is standard ISA UART that
349 // can be managed by this driver.
350 //
351 Status = EFI_SUCCESS;
352 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) {
353 Status = EFI_UNSUPPORTED;
354 goto Error;
355 }
356
357 Error:
358 //
359 // Close protocol, don't use device path protocol in the Support() function
360 //
361 gBS->CloseProtocol (
362 Controller,
363 &gEfiDevicePathProtocolGuid,
364 This->DriverBindingHandle,
365 Controller
366 );
367
368 return Status;
369 }
370
371 /**
372 Start to management the controller passed in
373
374 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
375 @param Controller The handle of the controller to test.
376 @param RemainingDevicePath A pointer to the remaining portion of a device path.
377
378 @return EFI_SUCCESS Driver is started successfully
379
380 **/
381 EFI_STATUS
382 EFIAPI
383 SerialControllerDriverStart (
384 IN EFI_DRIVER_BINDING_PROTOCOL *This,
385 IN EFI_HANDLE Controller,
386 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
387 )
388
389 {
390 EFI_STATUS Status;
391 EFI_ISA_IO_PROTOCOL *IsaIo;
392 SERIAL_DEV *SerialDevice;
393 UINTN Index;
394 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
395 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
396 UINTN EntryCount;
397 EFI_SERIAL_IO_PROTOCOL *SerialIo;
398 UART_DEVICE_PATH *Uart;
399 UINT32 FlowControlMap;
400 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
401 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
402 UINT32 Control;
403
404 SerialDevice = NULL;
405 //
406 // Get the Parent Device Path
407 //
408 Status = gBS->OpenProtocol (
409 Controller,
410 &gEfiDevicePathProtocolGuid,
411 (VOID **) &ParentDevicePath,
412 This->DriverBindingHandle,
413 Controller,
414 EFI_OPEN_PROTOCOL_BY_DRIVER
415 );
416 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
417 return Status;
418 }
419 //
420 // Report status code enable the serial
421 //
422 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
423 EFI_PROGRESS_CODE,
424 EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
425 ParentDevicePath
426 );
427
428 //
429 // Grab the IO abstraction we need to get any work done
430 //
431 Status = gBS->OpenProtocol (
432 Controller,
433 &gEfiIsaIoProtocolGuid,
434 (VOID **) &IsaIo,
435 This->DriverBindingHandle,
436 Controller,
437 EFI_OPEN_PROTOCOL_BY_DRIVER
438 );
439 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
440 goto Error;
441 }
442
443 if (Status == EFI_ALREADY_STARTED) {
444
445 if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
446 //
447 // If RemainingDevicePath is NULL or is the End of Device Path Node
448 //
449 return EFI_SUCCESS;
450 }
451
452 //
453 // Make sure a child handle does not already exist. This driver can only
454 // produce one child per serial port.
455 //
456 Status = gBS->OpenProtocolInformation (
457 Controller,
458 &gEfiIsaIoProtocolGuid,
459 &OpenInfoBuffer,
460 &EntryCount
461 );
462 if (EFI_ERROR (Status)) {
463 return Status;
464 }
465
466 Status = EFI_ALREADY_STARTED;
467 for (Index = 0; Index < EntryCount; Index++) {
468 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
469 Status = gBS->OpenProtocol (
470 OpenInfoBuffer[Index].ControllerHandle,
471 &gEfiSerialIoProtocolGuid,
472 (VOID **) &SerialIo,
473 This->DriverBindingHandle,
474 Controller,
475 EFI_OPEN_PROTOCOL_GET_PROTOCOL
476 );
477 if (!EFI_ERROR (Status)) {
478 Uart = (UART_DEVICE_PATH *) RemainingDevicePath;
479 Status = SerialIo->SetAttributes (
480 SerialIo,
481 Uart->BaudRate,
482 SerialIo->Mode->ReceiveFifoDepth,
483 SerialIo->Mode->Timeout,
484 (EFI_PARITY_TYPE) Uart->Parity,
485 Uart->DataBits,
486 (EFI_STOP_BITS_TYPE) Uart->StopBits
487 );
488
489 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
490 if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {
491 Status = SerialIo->GetControl (SerialIo, &Control);
492 if (!EFI_ERROR (Status)) {
493 if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
494 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
495 } else {
496 Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
497 }
498 //
499 // Clear the bits that are not allowed to pass to SetControl
500 //
501 Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
502 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
503 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
504 Status = SerialIo->SetControl (SerialIo, Control);
505 }
506 }
507 }
508 break;
509 }
510 }
511
512 FreePool (OpenInfoBuffer);
513 return Status;
514 }
515
516 if (RemainingDevicePath != NULL) {
517 if (IsDevicePathEnd (RemainingDevicePath)) {
518 //
519 // If RemainingDevicePath is the End of Device Path Node,
520 // skip enumerate any device and return EFI_SUCESSS
521 //
522 return EFI_SUCCESS;
523 }
524 }
525
526 //
527 // Initialize the serial device instance
528 //
529 SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTempate);
530 if (SerialDevice == NULL) {
531 Status = EFI_OUT_OF_RESOURCES;
532 goto Error;
533 }
534
535 SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);
536 SerialDevice->IsaIo = IsaIo;
537 SerialDevice->ParentDevicePath = ParentDevicePath;
538 FlowControl = NULL;
539 FlowControlMap = 0;
540
541 //
542 // Check if RemainingDevicePath is NULL,
543 // if yes, use the values from the gSerialDevTempate as no remaining device path was
544 // passed in.
545 //
546 if (RemainingDevicePath != NULL) {
547 //
548 // If RemainingDevicePath isn't NULL,
549 // match the configuration of the RemainingDevicePath. IsHandleSupported()
550 // already checked to make sure the RemainingDevicePath contains settings
551 // that we can support.
552 //
553 CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
554 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
555 if (IsUartFlowControlNode (FlowControl)) {
556 FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
557 } else {
558 FlowControl = NULL;
559 }
560 }
561
562 AddName (SerialDevice, IsaIo);
563
564 for (Index = 0; SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
565 if (SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
566 SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange;
567 }
568 }
569
570 SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
571
572 //
573 // Report status code the serial present
574 //
575 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
576 EFI_PROGRESS_CODE,
577 EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,
578 ParentDevicePath
579 );
580
581 if (!IsaSerialPortPresent (SerialDevice)) {
582 Status = EFI_DEVICE_ERROR;
583 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
584 EFI_ERROR_CODE,
585 EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
586 ParentDevicePath
587 );
588 goto Error;
589 }
590
591 //
592 // Build the device path by appending the UART node to the ParentDevicePath.
593 // The Uart setings are zero here, since SetAttribute() will update them to match
594 // the default setings.
595 //
596 SerialDevice->DevicePath = AppendDevicePathNode (
597 ParentDevicePath,
598 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
599 );
600 //
601 // Only produce the Flow Control node when remaining device path has it
602 //
603 if (FlowControl != NULL) {
604 TempDevicePath = SerialDevice->DevicePath;
605 if (TempDevicePath != NULL) {
606 SerialDevice->DevicePath = AppendDevicePathNode (
607 TempDevicePath,
608 (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
609 );
610 FreePool (TempDevicePath);
611 }
612 }
613 if (SerialDevice->DevicePath == NULL) {
614 Status = EFI_OUT_OF_RESOURCES;
615 goto Error;
616 }
617
618 //
619 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
620 //
621 SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;
622 SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;
623 SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity;
624 SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;
625
626 //
627 // Issue a reset to initialize the COM port
628 //
629 Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
630 if (EFI_ERROR (Status)) {
631 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
632 EFI_ERROR_CODE,
633 EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
634 ParentDevicePath
635 );
636 goto Error;
637 }
638 //
639 // Install protocol interfaces for the serial device.
640 //
641 Status = gBS->InstallMultipleProtocolInterfaces (
642 &SerialDevice->Handle,
643 &gEfiDevicePathProtocolGuid,
644 SerialDevice->DevicePath,
645 &gEfiSerialIoProtocolGuid,
646 &SerialDevice->SerialIo,
647 NULL
648 );
649 if (EFI_ERROR (Status)) {
650 goto Error;
651 }
652 //
653 // Open For Child Device
654 //
655 Status = gBS->OpenProtocol (
656 Controller,
657 &gEfiIsaIoProtocolGuid,
658 (VOID **) &IsaIo,
659 This->DriverBindingHandle,
660 SerialDevice->Handle,
661 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
662 );
663
664 Error:
665 if (EFI_ERROR (Status)) {
666 gBS->CloseProtocol (
667 Controller,
668 &gEfiDevicePathProtocolGuid,
669 This->DriverBindingHandle,
670 Controller
671 );
672 gBS->CloseProtocol (
673 Controller,
674 &gEfiIsaIoProtocolGuid,
675 This->DriverBindingHandle,
676 Controller
677 );
678 if (SerialDevice != NULL) {
679 if (SerialDevice->DevicePath != NULL) {
680 gBS->FreePool (SerialDevice->DevicePath);
681 }
682
683 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
684 gBS->FreePool (SerialDevice);
685 }
686 }
687
688 return Status;
689 }
690
691 /**
692 Disconnect this driver with the controller, uninstall related protocol instance
693
694 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
695 @param Controller The handle of the controller to test.
696 @param NumberOfChildren Number of child device.
697 @param ChildHandleBuffer A pointer to the remaining portion of a device path.
698
699 @retval EFI_SUCCESS Operation successfully
700 @retval EFI_DEVICE_ERROR Cannot stop the driver successfully
701
702 **/
703 EFI_STATUS
704 EFIAPI
705 SerialControllerDriverStop (
706 IN EFI_DRIVER_BINDING_PROTOCOL *This,
707 IN EFI_HANDLE Controller,
708 IN UINTN NumberOfChildren,
709 IN EFI_HANDLE *ChildHandleBuffer
710 )
711
712 {
713 EFI_STATUS Status;
714 UINTN Index;
715 BOOLEAN AllChildrenStopped;
716 EFI_SERIAL_IO_PROTOCOL *SerialIo;
717 SERIAL_DEV *SerialDevice;
718 EFI_ISA_IO_PROTOCOL *IsaIo;
719 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
720
721 Status = gBS->HandleProtocol (
722 Controller,
723 &gEfiDevicePathProtocolGuid,
724 (VOID **) &DevicePath
725 );
726
727 //
728 // Report the status code disable the serial
729 //
730 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
731 EFI_PROGRESS_CODE,
732 EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
733 DevicePath
734 );
735
736 //
737 // Complete all outstanding transactions to Controller.
738 // Don't allow any new transaction to Controller to be started.
739 //
740 if (NumberOfChildren == 0) {
741 //
742 // Close the bus driver
743 //
744 Status = gBS->CloseProtocol (
745 Controller,
746 &gEfiIsaIoProtocolGuid,
747 This->DriverBindingHandle,
748 Controller
749 );
750
751 Status = gBS->CloseProtocol (
752 Controller,
753 &gEfiDevicePathProtocolGuid,
754 This->DriverBindingHandle,
755 Controller
756 );
757 return Status;
758 }
759
760 AllChildrenStopped = TRUE;
761
762 for (Index = 0; Index < NumberOfChildren; Index++) {
763
764 Status = gBS->OpenProtocol (
765 ChildHandleBuffer[Index],
766 &gEfiSerialIoProtocolGuid,
767 (VOID **) &SerialIo,
768 This->DriverBindingHandle,
769 Controller,
770 EFI_OPEN_PROTOCOL_GET_PROTOCOL
771 );
772 if (!EFI_ERROR (Status)) {
773
774 SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
775
776 Status = gBS->CloseProtocol (
777 Controller,
778 &gEfiIsaIoProtocolGuid,
779 This->DriverBindingHandle,
780 ChildHandleBuffer[Index]
781 );
782
783 Status = gBS->UninstallMultipleProtocolInterfaces (
784 ChildHandleBuffer[Index],
785 &gEfiDevicePathProtocolGuid,
786 SerialDevice->DevicePath,
787 &gEfiSerialIoProtocolGuid,
788 &SerialDevice->SerialIo,
789 NULL
790 );
791 if (EFI_ERROR (Status)) {
792 gBS->OpenProtocol (
793 Controller,
794 &gEfiIsaIoProtocolGuid,
795 (VOID **) &IsaIo,
796 This->DriverBindingHandle,
797 ChildHandleBuffer[Index],
798 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
799 );
800 } else {
801 if (SerialDevice->DevicePath != NULL) {
802 gBS->FreePool (SerialDevice->DevicePath);
803 }
804
805 FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
806 gBS->FreePool (SerialDevice);
807 }
808 }
809
810 if (EFI_ERROR (Status)) {
811 AllChildrenStopped = FALSE;
812 }
813 }
814
815 if (!AllChildrenStopped) {
816 return EFI_DEVICE_ERROR;
817 }
818
819 return EFI_SUCCESS;
820 }
821
822 /**
823 Detect whether specific FIFO is full or not.
824
825 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
826
827 @return whether specific FIFO is full or not
828
829 **/
830 BOOLEAN
831 IsaSerialFifoFull (
832 IN SERIAL_DEV_FIFO *Fifo
833 )
834
835 {
836 if (Fifo->Surplus == 0) {
837 return TRUE;
838 }
839
840 return FALSE;
841 }
842
843 /**
844 Detect whether specific FIFO is empty or not.
845
846 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
847
848 @return whether specific FIFO is empty or not
849
850 **/
851 BOOLEAN
852 IsaSerialFifoEmpty (
853 IN SERIAL_DEV_FIFO *Fifo
854 )
855
856 {
857 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
858 return TRUE;
859 }
860
861 return FALSE;
862 }
863
864 /**
865 Add data to specific FIFO.
866
867 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
868 @param Data the data added to FIFO
869
870 @retval EFI_SUCCESS Add data to specific FIFO successfully
871 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full
872
873 **/
874 EFI_STATUS
875 IsaSerialFifoAdd (
876 IN SERIAL_DEV_FIFO *Fifo,
877 IN UINT8 Data
878 )
879
880 {
881 //
882 // if FIFO full can not add data
883 //
884 if (IsaSerialFifoFull (Fifo)) {
885 return EFI_OUT_OF_RESOURCES;
886 }
887 //
888 // FIFO is not full can add data
889 //
890 Fifo->Data[Fifo->Last] = Data;
891 Fifo->Surplus--;
892 Fifo->Last++;
893 if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {
894 Fifo->Last = 0;
895 }
896
897 return EFI_SUCCESS;
898 }
899
900 /**
901 Remove data from specific FIFO.
902
903 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
904 @param Data the data removed from FIFO
905
906 @retval EFI_SUCCESS Remove data from specific FIFO successfully
907 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty
908
909 **/
910 EFI_STATUS
911 IsaSerialFifoRemove (
912 IN SERIAL_DEV_FIFO *Fifo,
913 OUT UINT8 *Data
914 )
915
916 {
917 //
918 // if FIFO is empty, no data can remove
919 //
920 if (IsaSerialFifoEmpty (Fifo)) {
921 return EFI_OUT_OF_RESOURCES;
922 }
923 //
924 // FIFO is not empty, can remove data
925 //
926 *Data = Fifo->Data[Fifo->First];
927 Fifo->Surplus++;
928 Fifo->First++;
929 if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {
930 Fifo->First = 0;
931 }
932
933 return EFI_SUCCESS;
934 }
935
936 /**
937 Reads and writes all avaliable data.
938
939 @param SerialDevice The device to flush
940
941 @retval EFI_SUCCESS Data was read/written successfully.
942 @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when
943 this happens, pending writes are not done.
944
945 **/
946 EFI_STATUS
947 IsaSerialReceiveTransmit (
948 IN SERIAL_DEV *SerialDevice
949 )
950
951 {
952 SERIAL_PORT_LSR Lsr;
953 UINT8 Data;
954 BOOLEAN ReceiveFifoFull;
955 SERIAL_PORT_MSR Msr;
956 SERIAL_PORT_MCR Mcr;
957 UINTN TimeOut;
958
959 Data = 0;
960
961 //
962 // Begin the read or write
963 //
964 if (SerialDevice->SoftwareLoopbackEnable) {
965 do {
966 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
967 if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
968 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
969 if (ReceiveFifoFull) {
970 return EFI_OUT_OF_RESOURCES;
971 }
972
973 IsaSerialFifoAdd (&SerialDevice->Receive, Data);
974 }
975 } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));
976 } else {
977 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
978 //
979 // For full handshake flow control, tell the peer to send data
980 // if receive buffer is available.
981 //
982 if (SerialDevice->HardwareFlowControl &&
983 !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)&&
984 !ReceiveFifoFull
985 ) {
986 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
987 Mcr.Bits.Rts = 1;
988 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
989 }
990 do {
991 Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
992
993 //
994 // Flush incomming data to prevent a an overrun during a long write
995 //
996 if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
997 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
998 if (!ReceiveFifoFull) {
999 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
1000 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1001 EFI_ERROR_CODE,
1002 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1003 SerialDevice->DevicePath
1004 );
1005 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
1006 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1007 continue;
1008 }
1009 }
1010
1011 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1012
1013 IsaSerialFifoAdd (&SerialDevice->Receive, Data);
1014
1015 //
1016 // For full handshake flow control, if receive buffer full
1017 // tell the peer to stop sending data.
1018 //
1019 if (SerialDevice->HardwareFlowControl &&
1020 !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake) &&
1021 IsaSerialFifoFull (&SerialDevice->Receive)
1022 ) {
1023 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1024 Mcr.Bits.Rts = 0;
1025 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
1026 }
1027
1028
1029 continue;
1030 } else {
1031 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1032 EFI_PROGRESS_CODE,
1033 EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
1034 SerialDevice->DevicePath
1035 );
1036 }
1037 }
1038 //
1039 // Do the write
1040 //
1041 if (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
1042 //
1043 // Make sure the transmit data will not be missed
1044 //
1045 if (SerialDevice->HardwareFlowControl) {
1046 //
1047 // For half handshake flow control assert RTS before sending.
1048 //
1049 if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {
1050 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1051 Mcr.Bits.Rts= 0;
1052 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
1053 }
1054 //
1055 // Wait for CTS
1056 //
1057 TimeOut = 0;
1058 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1059 while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {
1060 gBS->Stall (TIMEOUT_STALL_INTERVAL);
1061 TimeOut++;
1062 if (TimeOut > 5) {
1063 break;
1064 }
1065
1066 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1067 }
1068
1069 if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {
1070 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
1071 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
1072 }
1073
1074 //
1075 // For half handshake flow control, tell DCE we are done.
1076 //
1077 if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {
1078 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1079 Mcr.Bits.Rts = 1;
1080 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
1081 }
1082 } else {
1083 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
1084 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
1085 }
1086 }
1087 } while (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit));
1088 }
1089
1090 return EFI_SUCCESS;
1091 }
1092
1093 //
1094 // Interface Functions
1095 //
1096 /**
1097 Reset serial device.
1098
1099 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1100
1101 @retval EFI_SUCCESS Reset successfully
1102 @retval EFI_DEVICE_ERROR Failed to reset
1103
1104 **/
1105 EFI_STATUS
1106 EFIAPI
1107 IsaSerialReset (
1108 IN EFI_SERIAL_IO_PROTOCOL *This
1109 )
1110 {
1111 EFI_STATUS Status;
1112 SERIAL_DEV *SerialDevice;
1113 SERIAL_PORT_LCR Lcr;
1114 SERIAL_PORT_IER Ier;
1115 SERIAL_PORT_MCR Mcr;
1116 SERIAL_PORT_FCR Fcr;
1117 EFI_TPL Tpl;
1118 UINT32 Control;
1119
1120 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1121
1122 //
1123 // Report the status code reset the serial
1124 //
1125 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1126 EFI_PROGRESS_CODE,
1127 EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
1128 SerialDevice->DevicePath
1129 );
1130
1131 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1132
1133 //
1134 // Make sure DLAB is 0.
1135 //
1136 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1137 Lcr.Bits.DLab = 0;
1138 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
1139
1140 //
1141 // Turn off all interrupts
1142 //
1143 Ier.Data = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1144 Ier.Bits.Ravie = 0;
1145 Ier.Bits.Theie = 0;
1146 Ier.Bits.Rie = 0;
1147 Ier.Bits.Mie = 0;
1148 WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data);
1149
1150 //
1151 // Disable the FIFO.
1152 //
1153 Fcr.Bits.TrFIFOE = 0;
1154 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
1155
1156 //
1157 // Turn off loopback and disable device interrupt.
1158 //
1159 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1160 Mcr.Bits.Out1 = 0;
1161 Mcr.Bits.Out2 = 0;
1162 Mcr.Bits.Lme = 0;
1163 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
1164
1165 //
1166 // Clear the scratch pad register
1167 //
1168 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0);
1169
1170 //
1171 // Go set the current attributes
1172 //
1173 Status = This->SetAttributes (
1174 This,
1175 This->Mode->BaudRate,
1176 This->Mode->ReceiveFifoDepth,
1177 This->Mode->Timeout,
1178 (EFI_PARITY_TYPE) This->Mode->Parity,
1179 (UINT8) This->Mode->DataBits,
1180 (EFI_STOP_BITS_TYPE) This->Mode->StopBits
1181 );
1182
1183 if (EFI_ERROR (Status)) {
1184 gBS->RestoreTPL (Tpl);
1185 return EFI_DEVICE_ERROR;
1186 }
1187 //
1188 // Go set the current control bits
1189 //
1190 Control = 0;
1191 if (SerialDevice->HardwareFlowControl) {
1192 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1193 }
1194 if (SerialDevice->SoftwareLoopbackEnable) {
1195 Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1196 }
1197 Status = This->SetControl (
1198 This,
1199 Control
1200 );
1201
1202 if (EFI_ERROR (Status)) {
1203 gBS->RestoreTPL (Tpl);
1204 return EFI_DEVICE_ERROR;
1205 }
1206 //
1207 // for 16550A enable FIFO, 16550 disable FIFO
1208 //
1209 Fcr.Bits.TrFIFOE = 1;
1210 Fcr.Bits.ResetRF = 1;
1211 Fcr.Bits.ResetTF = 1;
1212 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
1213
1214 //
1215 // Reset the software FIFO
1216 //
1217 SerialDevice->Receive.First = 0;
1218 SerialDevice->Receive.Last = 0;
1219 SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE;
1220 SerialDevice->Transmit.First = 0;
1221 SerialDevice->Transmit.Last = 0;
1222 SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE;
1223
1224 gBS->RestoreTPL (Tpl);
1225
1226 //
1227 // Device reset is complete
1228 //
1229 return EFI_SUCCESS;
1230 }
1231
1232 /**
1233 Set new attributes to a serial device.
1234
1235 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1236 @param BaudRate The baudrate of the serial device
1237 @param ReceiveFifoDepth The depth of receive FIFO buffer
1238 @param Timeout The request timeout for a single char
1239 @param Parity The type of parity used in serial device
1240 @param DataBits Number of databits used in serial device
1241 @param StopBits Number of stopbits used in serial device
1242
1243 @retval EFI_SUCCESS The new attributes were set
1244 @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value
1245 @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6
1246 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)
1247
1248 **/
1249 EFI_STATUS
1250 EFIAPI
1251 IsaSerialSetAttributes (
1252 IN EFI_SERIAL_IO_PROTOCOL *This,
1253 IN UINT64 BaudRate,
1254 IN UINT32 ReceiveFifoDepth,
1255 IN UINT32 Timeout,
1256 IN EFI_PARITY_TYPE Parity,
1257 IN UINT8 DataBits,
1258 IN EFI_STOP_BITS_TYPE StopBits
1259 )
1260 {
1261 EFI_STATUS Status;
1262 SERIAL_DEV *SerialDevice;
1263 UINT32 Divisor;
1264 UINT32 Remained;
1265 SERIAL_PORT_LCR Lcr;
1266 UART_DEVICE_PATH *Uart;
1267 EFI_TPL Tpl;
1268
1269 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1270
1271 //
1272 // Check for default settings and fill in actual values.
1273 //
1274 if (BaudRate == 0) {
1275 BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
1276 }
1277
1278 if (ReceiveFifoDepth == 0) {
1279 ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
1280 }
1281
1282 if (Timeout == 0) {
1283 Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
1284 }
1285
1286 if (Parity == DefaultParity) {
1287 Parity = (EFI_PARITY_TYPE)PcdGet8 (PcdUartDefaultParity);
1288 }
1289
1290 if (DataBits == 0) {
1291 DataBits = PcdGet8 (PcdUartDefaultDataBits);
1292 }
1293
1294 if (StopBits == DefaultStopBits) {
1295 StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
1296 }
1297 //
1298 // 5 and 6 data bits can not be verified on a 16550A UART
1299 // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings.
1300 //
1301 if ((DataBits == 5) || (DataBits == 6)) {
1302 return EFI_INVALID_PARAMETER;
1303 }
1304 //
1305 // Make sure all parameters are valid
1306 //
1307 if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
1308 return EFI_INVALID_PARAMETER;
1309 }
1310 //
1311 // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200,
1312 // 38400,57600,115200
1313 //
1314 if (BaudRate < 75) {
1315 BaudRate = 50;
1316 } else if (BaudRate < 110) {
1317 BaudRate = 75;
1318 } else if (BaudRate < 134) {
1319 BaudRate = 110;
1320 } else if (BaudRate < 150) {
1321 BaudRate = 134;
1322 } else if (BaudRate < 300) {
1323 BaudRate = 150;
1324 } else if (BaudRate < 600) {
1325 BaudRate = 300;
1326 } else if (BaudRate < 1200) {
1327 BaudRate = 600;
1328 } else if (BaudRate < 1800) {
1329 BaudRate = 1200;
1330 } else if (BaudRate < 2000) {
1331 BaudRate = 1800;
1332 } else if (BaudRate < 2400) {
1333 BaudRate = 2000;
1334 } else if (BaudRate < 3600) {
1335 BaudRate = 2400;
1336 } else if (BaudRate < 4800) {
1337 BaudRate = 3600;
1338 } else if (BaudRate < 7200) {
1339 BaudRate = 4800;
1340 } else if (BaudRate < 9600) {
1341 BaudRate = 7200;
1342 } else if (BaudRate < 19200) {
1343 BaudRate = 9600;
1344 } else if (BaudRate < 38400) {
1345 BaudRate = 19200;
1346 } else if (BaudRate < 57600) {
1347 BaudRate = 38400;
1348 } else if (BaudRate < 115200) {
1349 BaudRate = 57600;
1350 } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) {
1351 BaudRate = 115200;
1352 }
1353
1354 if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {
1355 return EFI_INVALID_PARAMETER;
1356 }
1357
1358 if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
1359 return EFI_INVALID_PARAMETER;
1360 }
1361
1362 if ((Parity < NoParity) || (Parity > SpaceParity)) {
1363 return EFI_INVALID_PARAMETER;
1364 }
1365
1366 if ((DataBits < 5) || (DataBits > 8)) {
1367 return EFI_INVALID_PARAMETER;
1368 }
1369
1370 if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
1371 return EFI_INVALID_PARAMETER;
1372 }
1373
1374 //
1375 // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits
1376 //
1377 if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {
1378 return EFI_INVALID_PARAMETER;
1379 }
1380
1381 //
1382 // Compute divisor use to program the baud rate using a round determination
1383 //
1384 Divisor = (UINT32) DivU64x32Remainder (
1385 SERIAL_PORT_INPUT_CLOCK,
1386 ((UINT32) BaudRate * 16),
1387 &Remained
1388 );
1389 if (Remained != 0) {
1390 Divisor += 1;
1391 }
1392
1393 if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) {
1394 return EFI_INVALID_PARAMETER;
1395 }
1396
1397 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1398
1399 //
1400 // Compute the actual baud rate that the serial port will be programmed for.
1401 //
1402 BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16;
1403
1404 //
1405 // Put serial port on Divisor Latch Mode
1406 //
1407 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1408 Lcr.Bits.DLab = 1;
1409 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
1410
1411 //
1412 // Write the divisor to the serial port
1413 //
1414 WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));
1415 WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));
1416
1417 //
1418 // Put serial port back in normal mode and set remaining attributes.
1419 //
1420 Lcr.Bits.DLab = 0;
1421
1422 switch (Parity) {
1423 case NoParity:
1424 Lcr.Bits.ParEn = 0;
1425 Lcr.Bits.EvenPar = 0;
1426 Lcr.Bits.SticPar = 0;
1427 break;
1428
1429 case EvenParity:
1430 Lcr.Bits.ParEn = 1;
1431 Lcr.Bits.EvenPar = 1;
1432 Lcr.Bits.SticPar = 0;
1433 break;
1434
1435 case OddParity:
1436 Lcr.Bits.ParEn = 1;
1437 Lcr.Bits.EvenPar = 0;
1438 Lcr.Bits.SticPar = 0;
1439 break;
1440
1441 case SpaceParity:
1442 Lcr.Bits.ParEn = 1;
1443 Lcr.Bits.EvenPar = 1;
1444 Lcr.Bits.SticPar = 1;
1445 break;
1446
1447 case MarkParity:
1448 Lcr.Bits.ParEn = 1;
1449 Lcr.Bits.EvenPar = 0;
1450 Lcr.Bits.SticPar = 1;
1451 break;
1452
1453 default:
1454 break;
1455 }
1456
1457 switch (StopBits) {
1458 case OneStopBit:
1459 Lcr.Bits.StopB = 0;
1460 break;
1461
1462 case OneFiveStopBits:
1463 case TwoStopBits:
1464 Lcr.Bits.StopB = 1;
1465 break;
1466
1467 default:
1468 break;
1469 }
1470 //
1471 // DataBits
1472 //
1473 Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
1474 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
1475
1476 //
1477 // Set the Serial I/O mode
1478 //
1479 This->Mode->BaudRate = BaudRate;
1480 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
1481 This->Mode->Timeout = Timeout;
1482 This->Mode->Parity = Parity;
1483 This->Mode->DataBits = DataBits;
1484 This->Mode->StopBits = StopBits;
1485
1486 //
1487 // See if Device Path Node has actually changed
1488 //
1489 if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
1490 SerialDevice->UartDevicePath.DataBits == DataBits &&
1491 SerialDevice->UartDevicePath.Parity == Parity &&
1492 SerialDevice->UartDevicePath.StopBits == StopBits
1493 ) {
1494 gBS->RestoreTPL (Tpl);
1495 return EFI_SUCCESS;
1496 }
1497 //
1498 // Update the device path
1499 //
1500 SerialDevice->UartDevicePath.BaudRate = BaudRate;
1501 SerialDevice->UartDevicePath.DataBits = DataBits;
1502 SerialDevice->UartDevicePath.Parity = (UINT8) Parity;
1503 SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
1504
1505 Status = EFI_SUCCESS;
1506 if (SerialDevice->Handle != NULL) {
1507 Uart = (UART_DEVICE_PATH *) (
1508 (UINTN) SerialDevice->DevicePath
1509 + GetDevicePathSize (SerialDevice->ParentDevicePath)
1510 - END_DEVICE_PATH_LENGTH
1511 );
1512 CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
1513 Status = gBS->ReinstallProtocolInterface (
1514 SerialDevice->Handle,
1515 &gEfiDevicePathProtocolGuid,
1516 SerialDevice->DevicePath,
1517 SerialDevice->DevicePath
1518 );
1519 }
1520
1521 gBS->RestoreTPL (Tpl);
1522
1523 return Status;
1524 }
1525
1526 /**
1527 Set Control Bits.
1528
1529 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1530 @param Control Control bits that can be settable
1531
1532 @retval EFI_SUCCESS New Control bits were set successfully
1533 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported
1534
1535 **/
1536 EFI_STATUS
1537 EFIAPI
1538 IsaSerialSetControl (
1539 IN EFI_SERIAL_IO_PROTOCOL *This,
1540 IN UINT32 Control
1541 )
1542 {
1543 SERIAL_DEV *SerialDevice;
1544 SERIAL_PORT_MCR Mcr;
1545 EFI_TPL Tpl;
1546 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
1547 EFI_STATUS Status;
1548
1549 //
1550 // The control bits that can be set are :
1551 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO
1552 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO
1553 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW
1554 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW
1555 // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
1556 //
1557 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1558
1559 //
1560 // first determine the parameter is invalid
1561 //
1562 if (Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
1563 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
1564 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) {
1565 return EFI_UNSUPPORTED;
1566 }
1567
1568 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1569
1570 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1571 Mcr.Bits.DtrC = 0;
1572 Mcr.Bits.Rts = 0;
1573 Mcr.Bits.Lme = 0;
1574 SerialDevice->SoftwareLoopbackEnable = FALSE;
1575 SerialDevice->HardwareFlowControl = FALSE;
1576
1577 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
1578 Mcr.Bits.DtrC = 1;
1579 }
1580
1581 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
1582 Mcr.Bits.Rts = 1;
1583 }
1584
1585 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
1586 Mcr.Bits.Lme = 1;
1587 }
1588
1589 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
1590 SerialDevice->HardwareFlowControl = TRUE;
1591 }
1592
1593 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
1594
1595 if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
1596 SerialDevice->SoftwareLoopbackEnable = TRUE;
1597 }
1598
1599 Status = EFI_SUCCESS;
1600 if (SerialDevice->Handle != NULL) {
1601 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
1602 (UINTN) SerialDevice->DevicePath
1603 + GetDevicePathSize (SerialDevice->ParentDevicePath)
1604 - END_DEVICE_PATH_LENGTH
1605 + sizeof (UART_DEVICE_PATH)
1606 );
1607 if (IsUartFlowControlNode (FlowControl) &&
1608 ((ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) ^ SerialDevice->HardwareFlowControl)) {
1609 //
1610 // Flow Control setting is changed, need to reinstall device path protocol
1611 //
1612 WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);
1613 Status = gBS->ReinstallProtocolInterface (
1614 SerialDevice->Handle,
1615 &gEfiDevicePathProtocolGuid,
1616 SerialDevice->DevicePath,
1617 SerialDevice->DevicePath
1618 );
1619 }
1620 }
1621
1622 gBS->RestoreTPL (Tpl);
1623
1624 return Status;
1625 }
1626
1627 /**
1628 Get ControlBits.
1629
1630 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1631 @param Control Control signals of the serial device
1632
1633 @retval EFI_SUCCESS Get Control signals successfully
1634
1635 **/
1636 EFI_STATUS
1637 EFIAPI
1638 IsaSerialGetControl (
1639 IN EFI_SERIAL_IO_PROTOCOL *This,
1640 OUT UINT32 *Control
1641 )
1642 {
1643 SERIAL_DEV *SerialDevice;
1644 SERIAL_PORT_MSR Msr;
1645 SERIAL_PORT_MCR Mcr;
1646 EFI_TPL Tpl;
1647
1648 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1649
1650 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1651
1652 *Control = 0;
1653
1654 //
1655 // Read the Modem Status Register
1656 //
1657 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1658
1659 if (Msr.Bits.Cts == 1) {
1660 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
1661 }
1662
1663 if (Msr.Bits.Dsr == 1) {
1664 *Control |= EFI_SERIAL_DATA_SET_READY;
1665 }
1666
1667 if (Msr.Bits.Ri == 1) {
1668 *Control |= EFI_SERIAL_RING_INDICATE;
1669 }
1670
1671 if (Msr.Bits.Dcd == 1) {
1672 *Control |= EFI_SERIAL_CARRIER_DETECT;
1673 }
1674 //
1675 // Read the Modem Control Register
1676 //
1677 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1678
1679 if (Mcr.Bits.DtrC == 1) {
1680 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1681 }
1682
1683 if (Mcr.Bits.Rts == 1) {
1684 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
1685 }
1686
1687 if (Mcr.Bits.Lme == 1) {
1688 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1689 }
1690
1691 if (SerialDevice->HardwareFlowControl) {
1692 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1693 }
1694 //
1695 // See if the Transmit FIFO is empty
1696 //
1697 IsaSerialReceiveTransmit (SerialDevice);
1698
1699 if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
1700 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
1701 }
1702 //
1703 // See if the Receive FIFO is empty.
1704 //
1705 IsaSerialReceiveTransmit (SerialDevice);
1706
1707 if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {
1708 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1709 }
1710
1711 if (SerialDevice->SoftwareLoopbackEnable) {
1712 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1713 }
1714
1715 gBS->RestoreTPL (Tpl);
1716
1717 return EFI_SUCCESS;
1718 }
1719
1720 /**
1721 Write the specified number of bytes to serial device.
1722
1723 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1724 @param BufferSize On input the size of Buffer, on output the amount of
1725 data actually written
1726 @param Buffer The buffer of data to write
1727
1728 @retval EFI_SUCCESS The data were written successfully
1729 @retval EFI_DEVICE_ERROR The device reported an error
1730 @retval EFI_TIMEOUT The write operation was stopped due to timeout
1731
1732 **/
1733 EFI_STATUS
1734 EFIAPI
1735 IsaSerialWrite (
1736 IN EFI_SERIAL_IO_PROTOCOL *This,
1737 IN OUT UINTN *BufferSize,
1738 IN VOID *Buffer
1739 )
1740 {
1741 SERIAL_DEV *SerialDevice;
1742 UINT8 *CharBuffer;
1743 UINT32 Index;
1744 UINTN Elapsed;
1745 UINTN ActualWrite;
1746 EFI_TPL Tpl;
1747
1748 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1749 Elapsed = 0;
1750 ActualWrite = 0;
1751
1752 if (*BufferSize == 0) {
1753 return EFI_SUCCESS;
1754 }
1755
1756 if (Buffer == NULL) {
1757 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1758 EFI_ERROR_CODE,
1759 EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1760 SerialDevice->DevicePath
1761 );
1762
1763 return EFI_DEVICE_ERROR;
1764 }
1765
1766 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1767
1768 CharBuffer = (UINT8 *) Buffer;
1769
1770 for (Index = 0; Index < *BufferSize; Index++) {
1771 IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
1772
1773 while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
1774 //
1775 // Unsuccessful write so check if timeout has expired, if not,
1776 // stall for a bit, increment time elapsed, and try again
1777 //
1778 if (Elapsed >= This->Mode->Timeout) {
1779 *BufferSize = ActualWrite;
1780 gBS->RestoreTPL (Tpl);
1781 return EFI_TIMEOUT;
1782 }
1783
1784 gBS->Stall (TIMEOUT_STALL_INTERVAL);
1785
1786 Elapsed += TIMEOUT_STALL_INTERVAL;
1787 }
1788
1789 ActualWrite++;
1790 //
1791 // Successful write so reset timeout
1792 //
1793 Elapsed = 0;
1794 }
1795
1796 gBS->RestoreTPL (Tpl);
1797
1798 return EFI_SUCCESS;
1799 }
1800
1801 /**
1802 Read the specified number of bytes from serial device.
1803
1804 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1805 @param BufferSize On input the size of Buffer, on output the amount of
1806 data returned in buffer
1807 @param Buffer The buffer to return the data into
1808
1809 @retval EFI_SUCCESS The data were read successfully
1810 @retval EFI_DEVICE_ERROR The device reported an error
1811 @retval EFI_TIMEOUT The read operation was stopped due to timeout
1812
1813 **/
1814 EFI_STATUS
1815 EFIAPI
1816 IsaSerialRead (
1817 IN EFI_SERIAL_IO_PROTOCOL *This,
1818 IN OUT UINTN *BufferSize,
1819 OUT VOID *Buffer
1820 )
1821 {
1822 SERIAL_DEV *SerialDevice;
1823 UINT32 Index;
1824 UINT8 *CharBuffer;
1825 UINTN Elapsed;
1826 EFI_STATUS Status;
1827 EFI_TPL Tpl;
1828
1829 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1830 Elapsed = 0;
1831
1832 if (*BufferSize == 0) {
1833 return EFI_SUCCESS;
1834 }
1835
1836 if (Buffer == NULL) {
1837 return EFI_DEVICE_ERROR;
1838 }
1839
1840 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1841
1842 Status = IsaSerialReceiveTransmit (SerialDevice);
1843
1844 if (EFI_ERROR (Status)) {
1845 *BufferSize = 0;
1846
1847 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1848 EFI_ERROR_CODE,
1849 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1850 SerialDevice->DevicePath
1851 );
1852
1853 gBS->RestoreTPL (Tpl);
1854
1855 return EFI_DEVICE_ERROR;
1856 }
1857
1858 CharBuffer = (UINT8 *) Buffer;
1859 for (Index = 0; Index < *BufferSize; Index++) {
1860 while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
1861 //
1862 // Unsuccessful read so check if timeout has expired, if not,
1863 // stall for a bit, increment time elapsed, and try again
1864 // Need this time out to get conspliter to work.
1865 //
1866 if (Elapsed >= This->Mode->Timeout) {
1867 *BufferSize = Index;
1868 gBS->RestoreTPL (Tpl);
1869 return EFI_TIMEOUT;
1870 }
1871
1872 gBS->Stall (TIMEOUT_STALL_INTERVAL);
1873 Elapsed += TIMEOUT_STALL_INTERVAL;
1874
1875 Status = IsaSerialReceiveTransmit (SerialDevice);
1876 if (Status == EFI_DEVICE_ERROR) {
1877 *BufferSize = Index;
1878 gBS->RestoreTPL (Tpl);
1879 return EFI_DEVICE_ERROR;
1880 }
1881 }
1882 //
1883 // Successful read so reset timeout
1884 //
1885 Elapsed = 0;
1886 }
1887
1888 IsaSerialReceiveTransmit (SerialDevice);
1889
1890 gBS->RestoreTPL (Tpl);
1891
1892 return EFI_SUCCESS;
1893 }
1894
1895 /**
1896 Use scratchpad register to test if this serial port is present.
1897
1898 @param SerialDevice Pointer to serial device structure
1899
1900 @return if this serial port is present
1901 **/
1902 BOOLEAN
1903 IsaSerialPortPresent (
1904 IN SERIAL_DEV *SerialDevice
1905 )
1906
1907 {
1908 UINT8 Temp;
1909 BOOLEAN Status;
1910
1911 Status = TRUE;
1912
1913 //
1914 // Save SCR reg
1915 //
1916 Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
1917 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);
1918
1919 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) {
1920 Status = FALSE;
1921 }
1922
1923 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);
1924
1925 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) {
1926 Status = FALSE;
1927 }
1928 //
1929 // Restore SCR
1930 //
1931 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);
1932 return Status;
1933 }
1934
1935 /**
1936 Use IsaIo protocol to read serial port.
1937
1938 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
1939 @param BaseAddress Serial port register group base address
1940 @param Offset Offset in register group
1941
1942 @return Data read from serial port
1943
1944 **/
1945 UINT8
1946 IsaSerialReadPort (
1947 IN EFI_ISA_IO_PROTOCOL *IsaIo,
1948 IN UINT16 BaseAddress,
1949 IN UINT32 Offset
1950 )
1951 {
1952 UINT8 Data;
1953
1954 //
1955 // Use IsaIo to access IO
1956 //
1957 IsaIo->Io.Read (
1958 IsaIo,
1959 EfiIsaIoWidthUint8,
1960 BaseAddress + Offset,
1961 1,
1962 &Data
1963 );
1964 return Data;
1965 }
1966
1967 /**
1968 Use IsaIo protocol to write serial port.
1969
1970 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
1971 @param BaseAddress Serial port register group base address
1972 @param Offset Offset in register group
1973 @param Data data which is to be written to some serial port register
1974
1975 **/
1976 VOID
1977 IsaSerialWritePort (
1978 IN EFI_ISA_IO_PROTOCOL *IsaIo,
1979 IN UINT16 BaseAddress,
1980 IN UINT32 Offset,
1981 IN UINT8 Data
1982 )
1983 {
1984 //
1985 // Use IsaIo to access IO
1986 //
1987 IsaIo->Io.Write (
1988 IsaIo,
1989 EfiIsaIoWidthUint8,
1990 BaseAddress + Offset,
1991 1,
1992 &Data
1993 );
1994 }
1995