PcAtChipsetPkg: Refine casting expression result to bigger size
[mirror_edk2.git] / PcAtChipsetPkg / Library / SerialIoLib / SerialPortLib.c
CommitLineData
f5752cb2 1/** @file\r
a9fd6721 2 UART Serial Port library functions\r
f5752cb2 3\r
bbbc509f 4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
95d48e82 5 This program and the accompanying materials\r
f5752cb2 6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
f5752cb2 15#include <Base.h>\r
78297266 16#include <Library/IoLib.h>\r
a9fd6721 17#include <Library/SerialPortLib.h>\r
f5752cb2 18\r
19//---------------------------------------------\r
20// UART Register Offsets\r
21//---------------------------------------------\r
22#define BAUD_LOW_OFFSET 0x00\r
23#define BAUD_HIGH_OFFSET 0x01\r
24#define IER_OFFSET 0x01\r
25#define LCR_SHADOW_OFFSET 0x01\r
26#define FCR_SHADOW_OFFSET 0x02\r
27#define IR_CONTROL_OFFSET 0x02\r
28#define FCR_OFFSET 0x02\r
29#define EIR_OFFSET 0x02\r
30#define BSR_OFFSET 0x03\r
31#define LCR_OFFSET 0x03\r
32#define MCR_OFFSET 0x04\r
33#define LSR_OFFSET 0x05\r
34#define MSR_OFFSET 0x06\r
35\r
36//---------------------------------------------\r
37// UART Register Bit Defines\r
38//---------------------------------------------\r
39#define LSR_TXRDY 0x20\r
40#define LSR_RXDA 0x01\r
41#define DLAB 0x01\r
d63a0df5
SZ
42#define MCR_DTRC 0x01\r
43#define MCR_RTS 0x02\r
44#define MSR_CTS 0x10\r
45#define MSR_DSR 0x20\r
46#define MSR_RI 0x40\r
47#define MSR_DCD 0x80\r
f5752cb2 48\r
78297266 49//---------------------------------------------\r
50// UART Settings\r
51//---------------------------------------------\r
52UINT16 gUartBase = 0x3F8;\r
53UINTN gBps = 115200;\r
54UINT8 gData = 8;\r
55UINT8 gStop = 1;\r
56UINT8 gParity = 0;\r
f5752cb2 57UINT8 gBreakSet = 0;\r
f5752cb2 58\r
78297266 59/**\r
60 Initialize the serial device hardware.\r
61 \r
62 If no initialization is required, then return RETURN_SUCCESS.\r
619ad10f 63 If the serial device was successfully initialized, then return RETURN_SUCCESS.\r
78297266 64 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.\r
65 \r
66 @retval RETURN_SUCCESS The serial device was initialized.\r
67 @retval RETURN_DEVICE_ERROR The serail device could not be initialized.\r
f5752cb2 68\r
69**/\r
70RETURN_STATUS\r
71EFIAPI\r
72SerialPortInitialize (\r
73 VOID\r
74 )\r
75{\r
78297266 76 UINTN Divisor;\r
77 UINT8 OutputData;\r
78 UINT8 Data;\r
f5752cb2 79\r
78297266 80 //\r
f5752cb2 81 // Map 5..8 to 0..3\r
82 //\r
78297266 83 Data = (UINT8) (gData - (UINT8) 5);\r
f5752cb2 84\r
85 //\r
86 // Calculate divisor for baud generator\r
87 //\r
78297266 88 Divisor = 115200 / gBps;\r
f5752cb2 89 \r
90 //\r
91 // Set communications format\r
92 //\r
78297266 93 OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
bbbc509f 94 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
f5752cb2 95\r
96 //\r
97 // Configure baud rate\r
98 //\r
bbbc509f
HW
99 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8) (Divisor >> 8));\r
100 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8) (Divisor & 0xff));\r
f5752cb2 101\r
102 //\r
103 // Switch back to bank 0\r
104 //\r
78297266 105 OutputData = (UINT8) ((~DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
bbbc509f 106 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
f5752cb2 107\r
108 return RETURN_SUCCESS;\r
109}\r
110\r
111/**\r
78297266 112 Write data from buffer to serial device. \r
113 \r
114 Writes NumberOfBytes data bytes from Buffer to the serial device. \r
115 The number of bytes actually written to the serial device is returned.\r
116 If the return value is less than NumberOfBytes, then the write operation failed.\r
f5752cb2 117\r
78297266 118 If Buffer is NULL, then ASSERT(). \r
f5752cb2 119\r
78297266 120 If NumberOfBytes is zero, then return 0.\r
121\r
122 @param Buffer Pointer to the data buffer to be written.\r
123 @param NumberOfBytes Number of bytes to written to the serial device.\r
124\r
125 @retval 0 NumberOfBytes is 0.\r
126 @retval >0 The number of bytes written to the serial device. \r
091a1262 127 If this value is less than NumberOfBytes, then the write operation failed.\r
f5752cb2 128\r
129**/\r
130UINTN\r
131EFIAPI\r
132SerialPortWrite (\r
133 IN UINT8 *Buffer,\r
134 IN UINTN NumberOfBytes\r
135)\r
136{\r
78297266 137 UINTN Result;\r
138 UINT8 Data;\r
f5752cb2 139\r
78297266 140 if (Buffer == NULL) {\r
f5752cb2 141 return 0;\r
142 }\r
143\r
144 Result = NumberOfBytes;\r
145\r
24115e44 146 while ((NumberOfBytes--) != 0) {\r
78297266 147 //\r
148 // Wait for the serail port to be ready.\r
149 //\r
150 do {\r
151 Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);\r
152 } while ((Data & LSR_TXRDY) == 0);\r
153 IoWrite8 ((UINT16) gUartBase, *Buffer++);\r
f5752cb2 154 }\r
155\r
156 return Result;\r
f5752cb2 157}\r
158\r
159\r
160/**\r
78297266 161 Reads data from a serial device into a buffer.\r
f5752cb2 162\r
78297266 163 @param Buffer Pointer to the data buffer to store the data read from the serial device.\r
164 @param NumberOfBytes Number of bytes to read from the serial device.\r
f5752cb2 165\r
78297266 166 @retval 0 NumberOfBytes is 0.\r
167 @retval >0 The number of bytes read from the serial device. \r
168 If this value is less than NumberOfBytes, then the read operation failed.\r
f5752cb2 169\r
170**/\r
171UINTN\r
172EFIAPI\r
173SerialPortRead (\r
174 OUT UINT8 *Buffer,\r
175 IN UINTN NumberOfBytes\r
176)\r
177{\r
78297266 178 UINTN Result;\r
179 UINT8 Data;\r
180\r
181 if (NULL == Buffer) {\r
182 return 0;\r
183 }\r
184\r
185 Result = NumberOfBytes;\r
186\r
24115e44 187 while ((NumberOfBytes--) != 0) {\r
78297266 188 //\r
189 // Wait for the serail port to be ready.\r
190 //\r
191 do {\r
192 Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);\r
193 } while ((Data & LSR_RXDA) == 0);\r
194\r
195 *Buffer++ = IoRead8 ((UINT16) gUartBase);\r
196 }\r
197\r
198 return Result;\r
199}\r
200\r
201/**\r
202 Polls a serial device to see if there is any data waiting to be read.\r
203\r
204 Polls aserial device to see if there is any data waiting to be read.\r
205 If there is data waiting to be read from the serial device, then TRUE is returned.\r
206 If there is no data waiting to be read from the serial device, then FALSE is returned.\r
207\r
208 @retval TRUE Data is waiting to be read from the serial device.\r
209 @retval FALSE There is no data waiting to be read from the serial device.\r
210\r
211**/\r
212BOOLEAN\r
213EFIAPI\r
214SerialPortPoll (\r
215 VOID\r
216 )\r
217{\r
218 UINT8 Data;\r
219\r
220 //\r
221 // Read the serial port status.\r
222 //\r
223 Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);\r
224\r
225 return (BOOLEAN) ((Data & LSR_RXDA) != 0);\r
f5752cb2 226}\r
227\r
d63a0df5
SZ
228/**\r
229 Sets the control bits on a serial device.\r
230\r
231 @param Control Sets the bits of Control that are settable.\r
232\r
233 @retval RETURN_SUCCESS The new control bits were set on the serial device.\r
234 @retval RETURN_UNSUPPORTED The serial device does not support this operation.\r
235 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.\r
236\r
237**/\r
238RETURN_STATUS\r
239EFIAPI\r
240SerialPortSetControl (\r
241 IN UINT32 Control\r
242 )\r
243{\r
244 UINT8 Mcr;\r
245\r
246 //\r
247 // First determine the parameter is invalid.\r
248 //\r
249 if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY))) != 0) {\r
250 return RETURN_UNSUPPORTED;\r
251 }\r
252\r
253 //\r
254 // Read the Modem Control Register.\r
255 //\r
256 Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET);\r
257 Mcr &= (~(MCR_DTRC | MCR_RTS));\r
258\r
259 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {\r
260 Mcr |= MCR_DTRC;\r
261 }\r
262\r
263 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {\r
264 Mcr |= MCR_RTS;\r
265 }\r
266\r
267 //\r
268 // Write the Modem Control Register.\r
269 //\r
270 IoWrite8 ((UINT16) gUartBase + MCR_OFFSET, Mcr);\r
271\r
272 return RETURN_SUCCESS;\r
273}\r
274\r
275/**\r
276 Retrieve the status of the control bits on a serial device.\r
277\r
278 @param Control A pointer to return the current control signals from the serial device.\r
279\r
280 @retval RETURN_SUCCESS The control bits were read from the serial device.\r
281 @retval RETURN_UNSUPPORTED The serial device does not support this operation.\r
282 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.\r
283\r
284**/\r
285RETURN_STATUS\r
286EFIAPI\r
287SerialPortGetControl (\r
288 OUT UINT32 *Control\r
289 )\r
290{\r
291 UINT8 Msr;\r
292 UINT8 Mcr;\r
293 UINT8 Lsr;\r
294\r
295 *Control = 0;\r
296\r
297 //\r
298 // Read the Modem Status Register.\r
299 //\r
300 Msr = IoRead8 ((UINT16) gUartBase + MSR_OFFSET);\r
301\r
302 if ((Msr & MSR_CTS) == MSR_CTS) {\r
303 *Control |= EFI_SERIAL_CLEAR_TO_SEND;\r
304 }\r
305\r
306 if ((Msr & MSR_DSR) == MSR_DSR) {\r
307 *Control |= EFI_SERIAL_DATA_SET_READY;\r
308 }\r
309\r
310 if ((Msr & MSR_RI) == MSR_RI) {\r
311 *Control |= EFI_SERIAL_RING_INDICATE;\r
312 }\r
313\r
314 if ((Msr & MSR_DCD) == MSR_DCD) {\r
315 *Control |= EFI_SERIAL_CARRIER_DETECT;\r
316 }\r
317\r
318 //\r
319 // Read the Modem Control Register.\r
320 //\r
321 Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET);\r
322\r
323 if ((Mcr & MCR_DTRC) == MCR_DTRC) {\r
324 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;\r
325 }\r
326\r
327 if ((Mcr & MCR_RTS) == MCR_RTS) {\r
328 *Control |= EFI_SERIAL_REQUEST_TO_SEND;\r
329 }\r
330\r
331 //\r
332 // Read the Line Status Register.\r
333 //\r
334 Lsr = IoRead8 ((UINT16) gUartBase + LSR_OFFSET);\r
335\r
336 if ((Lsr & LSR_TXRDY) == LSR_TXRDY) {\r
337 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;\r
338 }\r
339\r
340 if ((Lsr & LSR_RXDA) == 0) {\r
341 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;\r
342 }\r
343\r
344 return RETURN_SUCCESS;\r
345}\r
346\r
347/**\r
348 Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,\r
349 data bits, and stop bits on a serial device.\r
350\r
351 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the\r
352 device's default interface speed.\r
353 On output, the value actually set.\r
354 @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the\r
355 serial interface. A ReceiveFifoDepth value of 0 will use\r
356 the device's default FIFO depth.\r
357 On output, the value actually set.\r
358 @param Timeout The requested time out for a single character in microseconds.\r
359 This timeout applies to both the transmit and receive side of the\r
360 interface. A Timeout value of 0 will use the device's default time\r
361 out value.\r
362 On output, the value actually set.\r
363 @param Parity The type of parity to use on this serial device. A Parity value of\r
364 DefaultParity will use the device's default parity value.\r
365 On output, the value actually set.\r
366 @param DataBits The number of data bits to use on the serial device. A DataBits\r
367 vaule of 0 will use the device's default data bit setting.\r
368 On output, the value actually set.\r
369 @param StopBits The number of stop bits to use on this serial device. A StopBits\r
370 value of DefaultStopBits will use the device's default number of\r
371 stop bits.\r
372 On output, the value actually set.\r
373\r
374 @retval RETURN_SUCCESS The new attributes were set on the serial device.\r
375 @retval RETURN_UNSUPPORTED The serial device does not support this operation.\r
376 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.\r
377 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.\r
378\r
379**/\r
380RETURN_STATUS\r
381EFIAPI\r
382SerialPortSetAttributes (\r
383 IN OUT UINT64 *BaudRate,\r
384 IN OUT UINT32 *ReceiveFifoDepth,\r
385 IN OUT UINT32 *Timeout,\r
386 IN OUT EFI_PARITY_TYPE *Parity,\r
387 IN OUT UINT8 *DataBits,\r
388 IN OUT EFI_STOP_BITS_TYPE *StopBits\r
389 )\r
390{\r
391 UINTN Divisor;\r
392 UINT8 OutputData;\r
393 UINT8 LcrData;\r
394 UINT8 LcrParity;\r
395 UINT8 LcrStop;\r
396\r
397 //\r
398 // Check for default settings and fill in actual values.\r
399 //\r
400 if (*BaudRate == 0) {\r
401 *BaudRate = gBps;\r
402 }\r
403\r
404 if (*DataBits == 0) {\r
405 *DataBits = gData;\r
406 }\r
407\r
408 if (*Parity == DefaultParity) {\r
409 *Parity = NoParity;\r
410 }\r
411\r
412 if (*StopBits == DefaultStopBits) {\r
413 *StopBits = OneStopBit;\r
414 }\r
415\r
416 if ((*DataBits < 5) || (*DataBits > 8)) {\r
417 return RETURN_INVALID_PARAMETER;\r
418 }\r
419\r
d63a0df5
SZ
420 //\r
421 // Map 5..8 to 0..3\r
422 //\r
423 LcrData = (UINT8) (*DataBits - (UINT8) 5);\r
424\r
425 switch (*Parity) {\r
426 case NoParity:\r
427 LcrParity = 0;\r
428 break;\r
429\r
430 case EvenParity:\r
431 LcrParity = 3;\r
432 break;\r
433\r
434 case OddParity:\r
435 LcrParity = 1;\r
436 break;\r
437\r
438 case SpaceParity:\r
439 LcrParity = 7;\r
440 break;\r
441\r
442 case MarkParity:\r
443 LcrParity = 5;\r
444 break;\r
445\r
446 default:\r
de3ecb33 447 return RETURN_INVALID_PARAMETER;\r
d63a0df5
SZ
448 }\r
449\r
450 switch (*StopBits) {\r
451 case OneStopBit:\r
452 LcrStop = 0;\r
453 break;\r
454\r
455 case OneFiveStopBits:\r
456 case TwoStopBits:\r
457 LcrStop = 1;\r
458 break;\r
459\r
460 default:\r
de3ecb33 461 return RETURN_INVALID_PARAMETER;\r
d63a0df5
SZ
462 }\r
463\r
464 //\r
465 // Calculate divisor for baud generator\r
466 //\r
467 Divisor = 115200 / (UINTN) *BaudRate;\r
468\r
469 //\r
470 // Set communications format\r
471 //\r
472 OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);\r
bbbc509f 473 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
d63a0df5
SZ
474\r
475 //\r
476 // Configure baud rate\r
477 //\r
bbbc509f
HW
478 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8) (Divisor >> 8));\r
479 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8) (Divisor & 0xff));\r
d63a0df5
SZ
480\r
481 //\r
482 // Switch back to bank 0\r
483 //\r
484 OutputData = (UINT8) ((~DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);\r
bbbc509f 485 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
d63a0df5
SZ
486\r
487 return RETURN_SUCCESS;\r
488}\r
489\r