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