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