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