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