]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c
MdeModulePkg/PciSioSerialDxe: Flush Tx before config change
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciSioSerialDxe / SerialIo.c
1 /** @file
2 SerialIo implementation for PCI or SIO UARTs.
3
4 Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "Serial.h"
10
11 /**
12 Skip the optional Controller device path node and return the
13 pointer to the next device path node.
14
15 @param DevicePath Pointer to the device path.
16 @param ContainsControllerNode Returns TRUE if the Controller device path exists.
17 @param ControllerNumber Returns the Controller Number if Controller device path exists.
18
19 @return Pointer to the next device path node.
20 **/
21 UART_DEVICE_PATH *
22 SkipControllerDevicePathNode (
23 EFI_DEVICE_PATH_PROTOCOL *DevicePath,
24 BOOLEAN *ContainsControllerNode,
25 UINT32 *ControllerNumber
26 )
27 {
28 if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) &&
29 (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP)
30 ) {
31 if (ContainsControllerNode != NULL) {
32 *ContainsControllerNode = TRUE;
33 }
34 if (ControllerNumber != NULL) {
35 *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber;
36 }
37 DevicePath = NextDevicePathNode (DevicePath);
38 } else {
39 if (ContainsControllerNode != NULL) {
40 *ContainsControllerNode = FALSE;
41 }
42 }
43 return (UART_DEVICE_PATH *) DevicePath;
44 }
45
46 /**
47 Checks whether the UART parameters are valid and computes the Divisor.
48
49 @param ClockRate The clock rate of the serial device used to verify
50 the BaudRate. Do not verify the BaudRate if it's 0.
51 @param BaudRate The requested baudrate of the serial device.
52 @param DataBits Number of databits used in serial device.
53 @param Parity The type of parity used in serial device.
54 @param StopBits Number of stopbits used in serial device.
55 @param Divisor Return the divisor if ClockRate is not 0.
56 @param ActualBaudRate Return the actual supported baudrate without
57 exceeding BaudRate. NULL means baudrate degradation
58 is not allowed.
59 If the requested BaudRate is not supported, the routine
60 returns TRUE and the Actual Baud Rate when ActualBaudRate
61 is not NULL, returns FALSE when ActualBaudRate is NULL.
62
63 @retval TRUE The UART parameters are valid.
64 @retval FALSE The UART parameters are not valid.
65 **/
66 BOOLEAN
67 VerifyUartParameters (
68 IN UINT32 ClockRate,
69 IN UINT64 BaudRate,
70 IN UINT8 DataBits,
71 IN EFI_PARITY_TYPE Parity,
72 IN EFI_STOP_BITS_TYPE StopBits,
73 OUT UINT64 *Divisor,
74 OUT UINT64 *ActualBaudRate
75 )
76 {
77 UINT64 Remainder;
78 UINT32 ComputedBaudRate;
79 UINT64 ComputedDivisor;
80 UINT64 Percent;
81
82 if ((DataBits < 5) || (DataBits > 8) ||
83 (Parity < NoParity) || (Parity > SpaceParity) ||
84 (StopBits < OneStopBit) || (StopBits > TwoStopBits) ||
85 ((DataBits == 5) && (StopBits == TwoStopBits)) ||
86 ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits))
87 ) {
88 return FALSE;
89 }
90
91 //
92 // Do not verify the baud rate if clock rate is unknown (0).
93 //
94 if (ClockRate == 0) {
95 return TRUE;
96 }
97
98 //
99 // Compute divisor use to program the baud rate using a round determination
100 // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate)
101 // = ClockRate / (BaudRate << 4)
102 //
103 ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), &Remainder);
104 //
105 // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate)
106 // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3)
107 //
108 if (Remainder >= LShiftU64 (BaudRate, 3)) {
109 ComputedDivisor++;
110 }
111 //
112 // If the computed divisor is larger than the maximum value that can be programmed
113 // into the UART, then the requested baud rate can not be supported.
114 //
115 if (ComputedDivisor > MAX_UINT16) {
116 return FALSE;
117 }
118
119 //
120 // If the computed divisor is 0, then use a computed divisor of 1, which will select
121 // the maximum supported baud rate.
122 //
123 if (ComputedDivisor == 0) {
124 ComputedDivisor = 1;
125 }
126
127 //
128 // Actual baud rate that the serial port will be programmed for
129 // should be with in 4% of requested one.
130 //
131 ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
132 if (ComputedBaudRate == 0) {
133 return FALSE;
134 }
135
136 Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate);
137 DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));
138 DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));
139 DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
140
141 //
142 // If the requested BaudRate is not supported:
143 // Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL;
144 // Returns FALSE when ActualBaudRate is NULL.
145 //
146 if ((Percent >= 96) && (Percent <= 104)) {
147 if (ActualBaudRate != NULL) {
148 *ActualBaudRate = BaudRate;
149 }
150 if (Divisor != NULL) {
151 *Divisor = ComputedDivisor;
152 }
153 return TRUE;
154 }
155 if (ComputedBaudRate < BaudRate) {
156 if (ActualBaudRate != NULL) {
157 *ActualBaudRate = ComputedBaudRate;
158 }
159 if (Divisor != NULL) {
160 *Divisor = ComputedDivisor;
161 }
162 return TRUE;
163 }
164
165 //
166 // ActualBaudRate is higher than requested baud rate and more than 4%
167 // higher than the requested value. Increment Divisor if it is less
168 // than MAX_UINT16 and computed baud rate with new divisor.
169 //
170 if (ComputedDivisor == MAX_UINT16) {
171 return FALSE;
172 }
173 ComputedDivisor++;
174 ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4);
175 if (ComputedBaudRate == 0) {
176 return FALSE;
177 }
178
179 DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate));
180 DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor));
181 DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, ComputedBaudRate, Percent));
182
183 if (ActualBaudRate != NULL) {
184 *ActualBaudRate = ComputedBaudRate;
185 }
186 if (Divisor != NULL) {
187 *Divisor = ComputedDivisor;
188 }
189 return TRUE;
190 }
191
192 /**
193 Detect whether specific FIFO is full or not.
194
195 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
196
197 @return whether specific FIFO is full or not
198 **/
199 BOOLEAN
200 SerialFifoFull (
201 IN SERIAL_DEV_FIFO *Fifo
202 )
203 {
204 return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head);
205 }
206
207 /**
208 Detect whether specific FIFO is empty or not.
209
210 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
211
212 @return whether specific FIFO is empty or not
213 **/
214 BOOLEAN
215 SerialFifoEmpty (
216 IN SERIAL_DEV_FIFO *Fifo
217 )
218
219 {
220 return (BOOLEAN) (Fifo->Head == Fifo->Tail);
221 }
222
223 /**
224 Add data to specific FIFO.
225
226 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
227 @param Data the data added to FIFO
228
229 @retval EFI_SUCCESS Add data to specific FIFO successfully
230 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full
231 **/
232 EFI_STATUS
233 SerialFifoAdd (
234 IN OUT SERIAL_DEV_FIFO *Fifo,
235 IN UINT8 Data
236 )
237 {
238 //
239 // if FIFO full can not add data
240 //
241 if (SerialFifoFull (Fifo)) {
242 return EFI_OUT_OF_RESOURCES;
243 }
244 //
245 // FIFO is not full can add data
246 //
247 Fifo->Data[Fifo->Tail] = Data;
248 Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE;
249 return EFI_SUCCESS;
250 }
251
252 /**
253 Remove data from specific FIFO.
254
255 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
256 @param Data the data removed from FIFO
257
258 @retval EFI_SUCCESS Remove data from specific FIFO successfully
259 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty
260
261 **/
262 EFI_STATUS
263 SerialFifoRemove (
264 IN OUT SERIAL_DEV_FIFO *Fifo,
265 OUT UINT8 *Data
266 )
267 {
268 //
269 // if FIFO is empty, no data can remove
270 //
271 if (SerialFifoEmpty (Fifo)) {
272 return EFI_OUT_OF_RESOURCES;
273 }
274 //
275 // FIFO is not empty, can remove data
276 //
277 *Data = Fifo->Data[Fifo->Head];
278 Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE;
279 return EFI_SUCCESS;
280 }
281
282 /**
283 Reads and writes all available data.
284
285 @param SerialDevice The device to transmit.
286
287 @retval EFI_SUCCESS Data was read/written successfully.
288 @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when
289 this happens, pending writes are not done.
290
291 **/
292 EFI_STATUS
293 SerialReceiveTransmit (
294 IN SERIAL_DEV *SerialDevice
295 )
296
297 {
298 SERIAL_PORT_LSR Lsr;
299 UINT8 Data;
300 BOOLEAN ReceiveFifoFull;
301 SERIAL_PORT_MSR Msr;
302 SERIAL_PORT_MCR Mcr;
303 UINTN TimeOut;
304
305 Data = 0;
306
307 //
308 // Begin the read or write
309 //
310 if (SerialDevice->SoftwareLoopbackEnable) {
311 do {
312 ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
313 if (!SerialFifoEmpty (&SerialDevice->Transmit)) {
314 SerialFifoRemove (&SerialDevice->Transmit, &Data);
315 if (ReceiveFifoFull) {
316 return EFI_OUT_OF_RESOURCES;
317 }
318
319 SerialFifoAdd (&SerialDevice->Receive, Data);
320 }
321 } while (!SerialFifoEmpty (&SerialDevice->Transmit));
322 } else {
323 ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
324 //
325 // For full handshake flow control, tell the peer to send data
326 // if receive buffer is available.
327 //
328 if (SerialDevice->HardwareFlowControl &&
329 !FeaturePcdGet(PcdSerialUseHalfHandshake)&&
330 !ReceiveFifoFull
331 ) {
332 Mcr.Data = READ_MCR (SerialDevice);
333 Mcr.Bits.Rts = 1;
334 WRITE_MCR (SerialDevice, Mcr.Data);
335 }
336 do {
337 Lsr.Data = READ_LSR (SerialDevice);
338
339 //
340 // Flush incomming data to prevent a an overrun during a long write
341 //
342 if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
343 ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive);
344 if (!ReceiveFifoFull) {
345 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
346 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
347 EFI_ERROR_CODE,
348 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
349 SerialDevice->DevicePath
350 );
351 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
352 Data = READ_RBR (SerialDevice);
353 continue;
354 }
355 }
356
357 Data = READ_RBR (SerialDevice);
358
359 SerialFifoAdd (&SerialDevice->Receive, Data);
360
361 //
362 // For full handshake flow control, if receive buffer full
363 // tell the peer to stop sending data.
364 //
365 if (SerialDevice->HardwareFlowControl &&
366 !FeaturePcdGet(PcdSerialUseHalfHandshake) &&
367 SerialFifoFull (&SerialDevice->Receive)
368 ) {
369 Mcr.Data = READ_MCR (SerialDevice);
370 Mcr.Bits.Rts = 0;
371 WRITE_MCR (SerialDevice, Mcr.Data);
372 }
373
374
375 continue;
376 } else {
377 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
378 EFI_PROGRESS_CODE,
379 EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
380 SerialDevice->DevicePath
381 );
382 }
383 }
384 //
385 // Do the write
386 //
387 if (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)) {
388 //
389 // Make sure the transmit data will not be missed
390 //
391 if (SerialDevice->HardwareFlowControl) {
392 //
393 // For half handshake flow control assert RTS before sending.
394 //
395 if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
396 Mcr.Data = READ_MCR (SerialDevice);
397 Mcr.Bits.Rts= 0;
398 WRITE_MCR (SerialDevice, Mcr.Data);
399 }
400 //
401 // Wait for CTS
402 //
403 TimeOut = 0;
404 Msr.Data = READ_MSR (SerialDevice);
405 while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
406 gBS->Stall (TIMEOUT_STALL_INTERVAL);
407 TimeOut++;
408 if (TimeOut > 5) {
409 break;
410 }
411
412 Msr.Data = READ_MSR (SerialDevice);
413 }
414
415 if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdSerialUseHalfHandshake))) {
416 SerialFifoRemove (&SerialDevice->Transmit, &Data);
417 WRITE_THR (SerialDevice, Data);
418 }
419
420 //
421 // For half handshake flow control, tell DCE we are done.
422 //
423 if (FeaturePcdGet(PcdSerialUseHalfHandshake)) {
424 Mcr.Data = READ_MCR (SerialDevice);
425 Mcr.Bits.Rts = 1;
426 WRITE_MCR (SerialDevice, Mcr.Data);
427 }
428 } else {
429 SerialFifoRemove (&SerialDevice->Transmit, &Data);
430 WRITE_THR (SerialDevice, Data);
431 }
432 }
433 } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit));
434 }
435
436 return EFI_SUCCESS;
437 }
438
439 /**
440 Flush the serial hardware transmit FIFO, holding register, and shift register.
441
442 @param SerialDevice The device to flush.
443
444 @retval EFI_SUCCESS The transmit FIFO is completely flushed.
445 @retval EFI_TIMEOUT A timeout occured waiting for the transmit FIFO to flush.
446 **/
447 EFI_STATUS
448 SerialFlushTransmitFifo (
449 SERIAL_DEV *SerialDevice
450 )
451 {
452 SERIAL_PORT_LSR Lsr;
453 UINTN Timeout;
454 UINTN Elapsed;
455
456 //
457 // If this is the first time the UART is being configured, then the current
458 // UART settings are not known, so compute a timeout to wait for the Tx FIFO
459 // assuming the worst case current settings.
460 //
461 // Timeout = (Max Bits per Char) * (Max Pending Chars) / (Slowest Baud Rate)
462 // Max Bits per Char = Start bit + 8 data bits + parity + 2 stop bits = 12
463 // Max Pending Chars = Largest Tx FIFO + hold + shift = 64 + 1 + 1 = 66
464 // Slowest Reasonable Baud Rate = 300 baud
465 // Timeout = 12 * 66 / 300 = 2.64 seconds = 2,640,000 uS
466 //
467 Timeout = 2640000;
468
469 //
470 // Use the largest of the computed timeout, the default timeout, and the
471 // currently set timeout.
472 //
473 Timeout = MAX (Timeout, SERIAL_PORT_DEFAULT_TIMEOUT);
474 Timeout = MAX (Timeout, SerialDevice->SerialMode.Timeout);
475
476 //
477 // Wait for the shortest time possible for the serial port to be ready making
478 // sure the transmit FIFO, holding register, and shift register are all
479 // empty. The actual wait time is expected to be very small because the
480 // number characters currently in the FIFO should be small when a
481 // configuration change is requested.
482 //
483 // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
484 // in the rest of this function that may send additional characters to this
485 // UART device invalidating the flush operation.
486 //
487 Elapsed = 0;
488 Lsr.Data = READ_LSR (SerialDevice);
489 while (Lsr.Bits.Temt == 0 || Lsr.Bits.Thre == 0) {
490 if (Elapsed >= Timeout) {
491 return EFI_TIMEOUT;
492 }
493 gBS->Stall (TIMEOUT_STALL_INTERVAL);
494 Elapsed += TIMEOUT_STALL_INTERVAL;
495 Lsr.Data = READ_LSR (SerialDevice);
496 }
497
498 return EFI_SUCCESS;
499 }
500
501 //
502 // Interface Functions
503 //
504 /**
505 Reset serial device.
506
507 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
508
509 @retval EFI_SUCCESS Reset successfully
510 @retval EFI_DEVICE_ERROR Failed to reset
511
512 **/
513 EFI_STATUS
514 EFIAPI
515 SerialReset (
516 IN EFI_SERIAL_IO_PROTOCOL *This
517 )
518 {
519 EFI_STATUS Status;
520 SERIAL_DEV *SerialDevice;
521 SERIAL_PORT_LCR Lcr;
522 SERIAL_PORT_IER Ier;
523 SERIAL_PORT_MCR Mcr;
524 SERIAL_PORT_FCR Fcr;
525 EFI_TPL Tpl;
526 UINT32 Control;
527
528 SerialDevice = SERIAL_DEV_FROM_THIS (This);
529
530 //
531 // Report the status code reset the serial
532 //
533 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
534 EFI_PROGRESS_CODE,
535 EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
536 SerialDevice->DevicePath
537 );
538
539 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
540
541 //
542 // Wait for all data to be transmitted before changing the UART configuration.
543 //
544 // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
545 // that may send additional characters to this UART device until the UART
546 // configuration change is complete.
547 //
548 SerialFlushTransmitFifo (SerialDevice);
549
550 //
551 // Make sure DLAB is 0.
552 //
553 Lcr.Data = READ_LCR (SerialDevice);
554 Lcr.Bits.DLab = 0;
555 WRITE_LCR (SerialDevice, Lcr.Data);
556
557 //
558 // Turn off all interrupts
559 //
560 Ier.Data = READ_IER (SerialDevice);
561 Ier.Bits.Ravie = 0;
562 Ier.Bits.Theie = 0;
563 Ier.Bits.Rie = 0;
564 Ier.Bits.Mie = 0;
565 WRITE_IER (SerialDevice, Ier.Data);
566
567 //
568 // Reset the FIFO
569 //
570 Fcr.Data = 0;
571 Fcr.Bits.TrFIFOE = 0;
572 WRITE_FCR (SerialDevice, Fcr.Data);
573
574 //
575 // Turn off loopback and disable device interrupt.
576 //
577 Mcr.Data = READ_MCR (SerialDevice);
578 Mcr.Bits.Out1 = 0;
579 Mcr.Bits.Out2 = 0;
580 Mcr.Bits.Lme = 0;
581 WRITE_MCR (SerialDevice, Mcr.Data);
582
583 //
584 // Clear the scratch pad register
585 //
586 WRITE_SCR (SerialDevice, 0);
587
588 //
589 // Enable FIFO
590 //
591 Fcr.Bits.TrFIFOE = 1;
592 if (SerialDevice->ReceiveFifoDepth > 16) {
593 Fcr.Bits.TrFIFO64 = 1;
594 }
595 Fcr.Bits.ResetRF = 1;
596 Fcr.Bits.ResetTF = 1;
597 WRITE_FCR (SerialDevice, Fcr.Data);
598
599 //
600 // Go set the current attributes
601 //
602 Status = This->SetAttributes (
603 This,
604 This->Mode->BaudRate,
605 This->Mode->ReceiveFifoDepth,
606 This->Mode->Timeout,
607 (EFI_PARITY_TYPE) This->Mode->Parity,
608 (UINT8) This->Mode->DataBits,
609 (EFI_STOP_BITS_TYPE) This->Mode->StopBits
610 );
611
612 if (EFI_ERROR (Status)) {
613 gBS->RestoreTPL (Tpl);
614 return EFI_DEVICE_ERROR;
615 }
616 //
617 // Go set the current control bits
618 //
619 Control = 0;
620 if (SerialDevice->HardwareFlowControl) {
621 Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
622 }
623 if (SerialDevice->SoftwareLoopbackEnable) {
624 Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
625 }
626 Status = This->SetControl (
627 This,
628 Control
629 );
630
631 if (EFI_ERROR (Status)) {
632 gBS->RestoreTPL (Tpl);
633 return EFI_DEVICE_ERROR;
634 }
635
636 //
637 // Reset the software FIFO
638 //
639 SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0;
640 SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0;
641 gBS->RestoreTPL (Tpl);
642
643 //
644 // Device reset is complete
645 //
646 return EFI_SUCCESS;
647 }
648
649 /**
650 Set new attributes to a serial device.
651
652 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
653 @param BaudRate The baudrate of the serial device
654 @param ReceiveFifoDepth The depth of receive FIFO buffer
655 @param Timeout The request timeout for a single char
656 @param Parity The type of parity used in serial device
657 @param DataBits Number of databits used in serial device
658 @param StopBits Number of stopbits used in serial device
659
660 @retval EFI_SUCCESS The new attributes were set
661 @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value
662 @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6
663 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)
664
665 **/
666 EFI_STATUS
667 EFIAPI
668 SerialSetAttributes (
669 IN EFI_SERIAL_IO_PROTOCOL *This,
670 IN UINT64 BaudRate,
671 IN UINT32 ReceiveFifoDepth,
672 IN UINT32 Timeout,
673 IN EFI_PARITY_TYPE Parity,
674 IN UINT8 DataBits,
675 IN EFI_STOP_BITS_TYPE StopBits
676 )
677 {
678 EFI_STATUS Status;
679 SERIAL_DEV *SerialDevice;
680 UINT64 Divisor;
681 SERIAL_PORT_LCR Lcr;
682 UART_DEVICE_PATH *Uart;
683 EFI_TPL Tpl;
684
685 SerialDevice = SERIAL_DEV_FROM_THIS (This);
686
687 //
688 // Check for default settings and fill in actual values.
689 //
690 if (BaudRate == 0) {
691 BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
692 }
693
694 if (ReceiveFifoDepth == 0) {
695 ReceiveFifoDepth = SerialDevice->ReceiveFifoDepth;
696 }
697
698 if (Timeout == 0) {
699 Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
700 }
701
702 if (Parity == DefaultParity) {
703 Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity);
704 }
705
706 if (DataBits == 0) {
707 DataBits = PcdGet8 (PcdUartDefaultDataBits);
708 }
709
710 if (StopBits == DefaultStopBits) {
711 StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
712 }
713
714 if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, Parity, StopBits, &Divisor, &BaudRate)) {
715 return EFI_INVALID_PARAMETER;
716 }
717
718 if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > SerialDevice->ReceiveFifoDepth)) {
719 return EFI_INVALID_PARAMETER;
720 }
721
722 if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
723 return EFI_INVALID_PARAMETER;
724 }
725
726 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
727
728 //
729 // Wait for all data to be transmitted before changing the UART configuration.
730 //
731 // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
732 // that may send additional characters to this UART device until the UART
733 // configuration change is complete.
734 //
735 SerialFlushTransmitFifo (SerialDevice);
736
737 //
738 // Put serial port on Divisor Latch Mode
739 //
740 Lcr.Data = READ_LCR (SerialDevice);
741 Lcr.Bits.DLab = 1;
742 WRITE_LCR (SerialDevice, Lcr.Data);
743
744 //
745 // Write the divisor to the serial port
746 //
747 WRITE_DLL (SerialDevice, (UINT8) Divisor);
748 WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8));
749
750 //
751 // Put serial port back in normal mode and set remaining attributes.
752 //
753 Lcr.Bits.DLab = 0;
754
755 switch (Parity) {
756 case NoParity:
757 Lcr.Bits.ParEn = 0;
758 Lcr.Bits.EvenPar = 0;
759 Lcr.Bits.SticPar = 0;
760 break;
761
762 case EvenParity:
763 Lcr.Bits.ParEn = 1;
764 Lcr.Bits.EvenPar = 1;
765 Lcr.Bits.SticPar = 0;
766 break;
767
768 case OddParity:
769 Lcr.Bits.ParEn = 1;
770 Lcr.Bits.EvenPar = 0;
771 Lcr.Bits.SticPar = 0;
772 break;
773
774 case SpaceParity:
775 Lcr.Bits.ParEn = 1;
776 Lcr.Bits.EvenPar = 1;
777 Lcr.Bits.SticPar = 1;
778 break;
779
780 case MarkParity:
781 Lcr.Bits.ParEn = 1;
782 Lcr.Bits.EvenPar = 0;
783 Lcr.Bits.SticPar = 1;
784 break;
785
786 default:
787 break;
788 }
789
790 switch (StopBits) {
791 case OneStopBit:
792 Lcr.Bits.StopB = 0;
793 break;
794
795 case OneFiveStopBits:
796 case TwoStopBits:
797 Lcr.Bits.StopB = 1;
798 break;
799
800 default:
801 break;
802 }
803 //
804 // DataBits
805 //
806 Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
807 WRITE_LCR (SerialDevice, Lcr.Data);
808
809 //
810 // Set the Serial I/O mode
811 //
812 This->Mode->BaudRate = BaudRate;
813 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
814 This->Mode->Timeout = Timeout;
815 This->Mode->Parity = Parity;
816 This->Mode->DataBits = DataBits;
817 This->Mode->StopBits = StopBits;
818
819 //
820 // See if Device Path Node has actually changed
821 //
822 if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
823 SerialDevice->UartDevicePath.DataBits == DataBits &&
824 SerialDevice->UartDevicePath.Parity == Parity &&
825 SerialDevice->UartDevicePath.StopBits == StopBits
826 ) {
827 gBS->RestoreTPL (Tpl);
828 return EFI_SUCCESS;
829 }
830 //
831 // Update the device path
832 //
833 SerialDevice->UartDevicePath.BaudRate = BaudRate;
834 SerialDevice->UartDevicePath.DataBits = DataBits;
835 SerialDevice->UartDevicePath.Parity = (UINT8) Parity;
836 SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
837
838 Status = EFI_SUCCESS;
839 if (SerialDevice->Handle != NULL) {
840
841 //
842 // Skip the optional Controller device path node
843 //
844 Uart = SkipControllerDevicePathNode (
845 (EFI_DEVICE_PATH_PROTOCOL *) (
846 (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH
847 ),
848 NULL,
849 NULL
850 );
851 CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
852 Status = gBS->ReinstallProtocolInterface (
853 SerialDevice->Handle,
854 &gEfiDevicePathProtocolGuid,
855 SerialDevice->DevicePath,
856 SerialDevice->DevicePath
857 );
858 }
859
860 gBS->RestoreTPL (Tpl);
861
862 return Status;
863 }
864
865 /**
866 Set Control Bits.
867
868 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
869 @param Control Control bits that can be settable
870
871 @retval EFI_SUCCESS New Control bits were set successfully
872 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported
873
874 **/
875 EFI_STATUS
876 EFIAPI
877 SerialSetControl (
878 IN EFI_SERIAL_IO_PROTOCOL *This,
879 IN UINT32 Control
880 )
881 {
882 SERIAL_DEV *SerialDevice;
883 SERIAL_PORT_MCR Mcr;
884 EFI_TPL Tpl;
885 UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
886 EFI_STATUS Status;
887
888 //
889 // The control bits that can be set are :
890 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO
891 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO
892 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW
893 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW
894 // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
895 //
896 SerialDevice = SERIAL_DEV_FROM_THIS (This);
897
898 //
899 // first determine the parameter is invalid
900 //
901 if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
902 EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
903 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
904 return EFI_UNSUPPORTED;
905 }
906
907 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
908
909 //
910 // Wait for all data to be transmitted before changing the UART configuration.
911 //
912 // NOTE: Do not use any DEBUG() or REPORT_STATUS_CODE() or any other calls
913 // that may send additional characters to this UART device until the UART
914 // configuration change is complete.
915 //
916 SerialFlushTransmitFifo (SerialDevice);
917
918 Mcr.Data = READ_MCR (SerialDevice);
919 Mcr.Bits.DtrC = 0;
920 Mcr.Bits.Rts = 0;
921 Mcr.Bits.Lme = 0;
922 SerialDevice->SoftwareLoopbackEnable = FALSE;
923 SerialDevice->HardwareFlowControl = FALSE;
924
925 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
926 Mcr.Bits.DtrC = 1;
927 }
928
929 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
930 Mcr.Bits.Rts = 1;
931 }
932
933 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
934 Mcr.Bits.Lme = 1;
935 }
936
937 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
938 SerialDevice->HardwareFlowControl = TRUE;
939 }
940
941 WRITE_MCR (SerialDevice, Mcr.Data);
942
943 if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
944 SerialDevice->SoftwareLoopbackEnable = TRUE;
945 }
946
947 Status = EFI_SUCCESS;
948 if (SerialDevice->Handle != NULL) {
949 FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
950 (UINTN) SerialDevice->DevicePath
951 + GetDevicePathSize (SerialDevice->ParentDevicePath)
952 - END_DEVICE_PATH_LENGTH
953 + sizeof (UART_DEVICE_PATH)
954 );
955 if (IsUartFlowControlDevicePathNode (FlowControl) &&
956 ((BOOLEAN) (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) != SerialDevice->HardwareFlowControl)) {
957 //
958 // Flow Control setting is changed, need to reinstall device path protocol
959 //
960 WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);
961 Status = gBS->ReinstallProtocolInterface (
962 SerialDevice->Handle,
963 &gEfiDevicePathProtocolGuid,
964 SerialDevice->DevicePath,
965 SerialDevice->DevicePath
966 );
967 }
968 }
969
970 gBS->RestoreTPL (Tpl);
971
972 return Status;
973 }
974
975 /**
976 Get ControlBits.
977
978 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
979 @param Control Control signals of the serial device
980
981 @retval EFI_SUCCESS Get Control signals successfully
982
983 **/
984 EFI_STATUS
985 EFIAPI
986 SerialGetControl (
987 IN EFI_SERIAL_IO_PROTOCOL *This,
988 OUT UINT32 *Control
989 )
990 {
991 SERIAL_DEV *SerialDevice;
992 SERIAL_PORT_MSR Msr;
993 SERIAL_PORT_MCR Mcr;
994 EFI_TPL Tpl;
995
996 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
997
998 SerialDevice = SERIAL_DEV_FROM_THIS (This);
999
1000 *Control = 0;
1001
1002 //
1003 // Read the Modem Status Register
1004 //
1005 Msr.Data = READ_MSR (SerialDevice);
1006
1007 if (Msr.Bits.Cts == 1) {
1008 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
1009 }
1010
1011 if (Msr.Bits.Dsr == 1) {
1012 *Control |= EFI_SERIAL_DATA_SET_READY;
1013 }
1014
1015 if (Msr.Bits.Ri == 1) {
1016 *Control |= EFI_SERIAL_RING_INDICATE;
1017 }
1018
1019 if (Msr.Bits.Dcd == 1) {
1020 *Control |= EFI_SERIAL_CARRIER_DETECT;
1021 }
1022 //
1023 // Read the Modem Control Register
1024 //
1025 Mcr.Data = READ_MCR (SerialDevice);
1026
1027 if (Mcr.Bits.DtrC == 1) {
1028 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1029 }
1030
1031 if (Mcr.Bits.Rts == 1) {
1032 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
1033 }
1034
1035 if (Mcr.Bits.Lme == 1) {
1036 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1037 }
1038
1039 if (SerialDevice->HardwareFlowControl) {
1040 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1041 }
1042 //
1043 // Update FIFO status
1044 //
1045 SerialReceiveTransmit (SerialDevice);
1046
1047 //
1048 // See if the Transmit FIFO is empty
1049 //
1050 if (SerialFifoEmpty (&SerialDevice->Transmit)) {
1051 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
1052 }
1053
1054 //
1055 // See if the Receive FIFO is empty.
1056 //
1057 if (SerialFifoEmpty (&SerialDevice->Receive)) {
1058 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1059 }
1060
1061 if (SerialDevice->SoftwareLoopbackEnable) {
1062 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1063 }
1064
1065 gBS->RestoreTPL (Tpl);
1066
1067 return EFI_SUCCESS;
1068 }
1069
1070 /**
1071 Write the specified number of bytes to serial device.
1072
1073 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1074 @param BufferSize On input the size of Buffer, on output the amount of
1075 data actually written
1076 @param Buffer The buffer of data to write
1077
1078 @retval EFI_SUCCESS The data were written successfully
1079 @retval EFI_DEVICE_ERROR The device reported an error
1080 @retval EFI_TIMEOUT The write operation was stopped due to timeout
1081
1082 **/
1083 EFI_STATUS
1084 EFIAPI
1085 SerialWrite (
1086 IN EFI_SERIAL_IO_PROTOCOL *This,
1087 IN OUT UINTN *BufferSize,
1088 IN VOID *Buffer
1089 )
1090 {
1091 SERIAL_DEV *SerialDevice;
1092 UINT8 *CharBuffer;
1093 UINT32 Index;
1094 UINTN Elapsed;
1095 UINTN ActualWrite;
1096 EFI_TPL Tpl;
1097 UINTN Timeout;
1098 UINTN BitsPerCharacter;
1099
1100 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1101 Elapsed = 0;
1102 ActualWrite = 0;
1103
1104 if (*BufferSize == 0) {
1105 return EFI_SUCCESS;
1106 }
1107
1108 if (Buffer == NULL) {
1109 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1110 EFI_ERROR_CODE,
1111 EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1112 SerialDevice->DevicePath
1113 );
1114
1115 return EFI_DEVICE_ERROR;
1116 }
1117
1118 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1119
1120 CharBuffer = (UINT8 *) Buffer;
1121
1122 //
1123 // Compute the number of bits in a single character. This is a start bit,
1124 // followed by the number of data bits, followed by the number of stop bits.
1125 // The number of stop bits is specified by an enumeration that includes
1126 // support for 1.5 stop bits. Treat 1.5 stop bits as 2 stop bits.
1127 //
1128 BitsPerCharacter =
1129 1 +
1130 This->Mode->DataBits +
1131 ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits);
1132
1133 //
1134 // Compute the timeout in microseconds to wait for a single byte to be
1135 // transmitted. The Mode structure contans a Timeout field that is the
1136 // maximum time to transmit or receive a character. However, many UARTs
1137 // have a FIFO for transmits, so the time required to add one new character
1138 // to the transmit FIFO may be the time required to flush a full FIFO. If
1139 // the Timeout in the Mode structure is smaller than the time required to
1140 // flush a full FIFO at the current baud rate, then use a timeout value that
1141 // is required to flush a full transmit FIFO.
1142 //
1143 Timeout = MAX (
1144 This->Mode->Timeout,
1145 (UINTN)DivU64x64Remainder (
1146 BitsPerCharacter * (SerialDevice->TransmitFifoDepth + 1) * 1000000,
1147 This->Mode->BaudRate,
1148 NULL
1149 )
1150 );
1151
1152 for (Index = 0; Index < *BufferSize; Index++) {
1153 SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
1154
1155 while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !SerialFifoEmpty (&SerialDevice->Transmit)) {
1156 //
1157 // Unsuccessful write so check if timeout has expired, if not,
1158 // stall for a bit, increment time elapsed, and try again
1159 //
1160 if (Elapsed >= Timeout) {
1161 *BufferSize = ActualWrite;
1162 gBS->RestoreTPL (Tpl);
1163 return EFI_TIMEOUT;
1164 }
1165
1166 gBS->Stall (TIMEOUT_STALL_INTERVAL);
1167
1168 Elapsed += TIMEOUT_STALL_INTERVAL;
1169 }
1170
1171 ActualWrite++;
1172 //
1173 // Successful write so reset timeout
1174 //
1175 Elapsed = 0;
1176 }
1177
1178 gBS->RestoreTPL (Tpl);
1179
1180 return EFI_SUCCESS;
1181 }
1182
1183 /**
1184 Read the specified number of bytes from serial device.
1185
1186 @param This Pointer to EFI_SERIAL_IO_PROTOCOL
1187 @param BufferSize On input the size of Buffer, on output the amount of
1188 data returned in buffer
1189 @param Buffer The buffer to return the data into
1190
1191 @retval EFI_SUCCESS The data were read successfully
1192 @retval EFI_DEVICE_ERROR The device reported an error
1193 @retval EFI_TIMEOUT The read operation was stopped due to timeout
1194
1195 **/
1196 EFI_STATUS
1197 EFIAPI
1198 SerialRead (
1199 IN EFI_SERIAL_IO_PROTOCOL *This,
1200 IN OUT UINTN *BufferSize,
1201 OUT VOID *Buffer
1202 )
1203 {
1204 SERIAL_DEV *SerialDevice;
1205 UINT32 Index;
1206 UINT8 *CharBuffer;
1207 UINTN Elapsed;
1208 EFI_STATUS Status;
1209 EFI_TPL Tpl;
1210
1211 SerialDevice = SERIAL_DEV_FROM_THIS (This);
1212 Elapsed = 0;
1213
1214 if (*BufferSize == 0) {
1215 return EFI_SUCCESS;
1216 }
1217
1218 if (Buffer == NULL) {
1219 return EFI_DEVICE_ERROR;
1220 }
1221
1222 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1223
1224 Status = SerialReceiveTransmit (SerialDevice);
1225
1226 if (EFI_ERROR (Status)) {
1227 *BufferSize = 0;
1228
1229 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1230 EFI_ERROR_CODE,
1231 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
1232 SerialDevice->DevicePath
1233 );
1234
1235 gBS->RestoreTPL (Tpl);
1236
1237 return EFI_DEVICE_ERROR;
1238 }
1239
1240 CharBuffer = (UINT8 *) Buffer;
1241 for (Index = 0; Index < *BufferSize; Index++) {
1242 while (SerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
1243 //
1244 // Unsuccessful read so check if timeout has expired, if not,
1245 // stall for a bit, increment time elapsed, and try again
1246 // Need this time out to get conspliter to work.
1247 //
1248 if (Elapsed >= This->Mode->Timeout) {
1249 *BufferSize = Index;
1250 gBS->RestoreTPL (Tpl);
1251 return EFI_TIMEOUT;
1252 }
1253
1254 gBS->Stall (TIMEOUT_STALL_INTERVAL);
1255 Elapsed += TIMEOUT_STALL_INTERVAL;
1256
1257 Status = SerialReceiveTransmit (SerialDevice);
1258 if (Status == EFI_DEVICE_ERROR) {
1259 *BufferSize = Index;
1260 gBS->RestoreTPL (Tpl);
1261 return EFI_DEVICE_ERROR;
1262 }
1263 }
1264 //
1265 // Successful read so reset timeout
1266 //
1267 Elapsed = 0;
1268 }
1269
1270 SerialReceiveTransmit (SerialDevice);
1271
1272 gBS->RestoreTPL (Tpl);
1273
1274 return EFI_SUCCESS;
1275 }
1276
1277 /**
1278 Use scratchpad register to test if this serial port is present.
1279
1280 @param SerialDevice Pointer to serial device structure
1281
1282 @return if this serial port is present
1283 **/
1284 BOOLEAN
1285 SerialPresent (
1286 IN SERIAL_DEV *SerialDevice
1287 )
1288
1289 {
1290 UINT8 Temp;
1291 BOOLEAN Status;
1292
1293 Status = TRUE;
1294
1295 //
1296 // Save SCR reg
1297 //
1298 Temp = READ_SCR (SerialDevice);
1299 WRITE_SCR (SerialDevice, 0xAA);
1300
1301 if (READ_SCR (SerialDevice) != 0xAA) {
1302 Status = FALSE;
1303 }
1304
1305 WRITE_SCR (SerialDevice, 0x55);
1306
1307 if (READ_SCR (SerialDevice) != 0x55) {
1308 Status = FALSE;
1309 }
1310 //
1311 // Restore SCR
1312 //
1313 WRITE_SCR (SerialDevice, Temp);
1314 return Status;
1315 }
1316
1317 /**
1318 Read serial port.
1319
1320 @param SerialDev Pointer to serial device
1321 @param Offset Offset in register group
1322
1323 @return Data read from serial port
1324
1325 **/
1326 UINT8
1327 SerialReadRegister (
1328 IN SERIAL_DEV *SerialDev,
1329 IN UINT32 Offset
1330 )
1331 {
1332 UINT8 Data;
1333 EFI_STATUS Status;
1334
1335 if (SerialDev->PciDeviceInfo == NULL) {
1336 return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride);
1337 } else {
1338 if (SerialDev->MmioAccess) {
1339 Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1340 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1341 } else {
1342 Status = SerialDev->PciDeviceInfo->PciIo->Io.Read (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1343 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1344 }
1345 ASSERT_EFI_ERROR (Status);
1346 return Data;
1347 }
1348 }
1349
1350 /**
1351 Write serial port.
1352
1353 @param SerialDev Pointer to serial device
1354 @param Offset Offset in register group
1355 @param Data data which is to be written to some serial port register
1356 **/
1357 VOID
1358 SerialWriteRegister (
1359 IN SERIAL_DEV *SerialDev,
1360 IN UINT32 Offset,
1361 IN UINT8 Data
1362 )
1363 {
1364 EFI_STATUS Status;
1365
1366 if (SerialDev->PciDeviceInfo == NULL) {
1367 IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, Data);
1368 } else {
1369 if (SerialDev->MmioAccess) {
1370 Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1371 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1372 } else {
1373 Status = SerialDev->PciDeviceInfo->PciIo->Io.Write (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR,
1374 SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data);
1375 }
1376 ASSERT_EFI_ERROR (Status);
1377 }
1378 }