]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c
PcAtChipsetPkg: Clean up source files
[mirror_edk2.git] / PcAtChipsetPkg / Library / SerialIoLib / SerialPortLib.c
... / ...
CommitLineData
1/** @file\r
2 UART Serial Port library functions\r
3\r
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
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
15#include <Base.h>\r
16#include <Library/IoLib.h>\r
17#include <Library/SerialPortLib.h>\r
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
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
48\r
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
57UINT8 gBreakSet = 0;\r
58\r
59/**\r
60 Initialize the serial device hardware.\r
61\r
62 If no initialization is required, then return RETURN_SUCCESS.\r
63 If the serial device was successfully initialized, then return RETURN_SUCCESS.\r
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
68\r
69**/\r
70RETURN_STATUS\r
71EFIAPI\r
72SerialPortInitialize (\r
73 VOID\r
74 )\r
75{\r
76 UINTN Divisor;\r
77 UINT8 OutputData;\r
78 UINT8 Data;\r
79\r
80 //\r
81 // Map 5..8 to 0..3\r
82 //\r
83 Data = (UINT8) (gData - (UINT8) 5);\r
84\r
85 //\r
86 // Calculate divisor for baud generator\r
87 //\r
88 Divisor = 115200 / gBps;\r
89\r
90 //\r
91 // Set communications format\r
92 //\r
93 OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
94 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
95\r
96 //\r
97 // Configure baud rate\r
98 //\r
99 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8) (Divisor >> 8));\r
100 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8) (Divisor & 0xff));\r
101\r
102 //\r
103 // Switch back to bank 0\r
104 //\r
105 OutputData = (UINT8) ( (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);\r
106 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
107\r
108 return RETURN_SUCCESS;\r
109}\r
110\r
111/**\r
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
117\r
118 If Buffer is NULL, then ASSERT().\r
119\r
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
127 If this value is less than NumberOfBytes, then the write operation failed.\r
128\r
129**/\r
130UINTN\r
131EFIAPI\r
132SerialPortWrite (\r
133 IN UINT8 *Buffer,\r
134 IN UINTN NumberOfBytes\r
135)\r
136{\r
137 UINTN Result;\r
138 UINT8 Data;\r
139\r
140 if (Buffer == NULL) {\r
141 return 0;\r
142 }\r
143\r
144 Result = NumberOfBytes;\r
145\r
146 while ((NumberOfBytes--) != 0) {\r
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
154 }\r
155\r
156 return Result;\r
157}\r
158\r
159\r
160/**\r
161 Reads data from a serial device into a buffer.\r
162\r
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
165\r
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
169\r
170**/\r
171UINTN\r
172EFIAPI\r
173SerialPortRead (\r
174 OUT UINT8 *Buffer,\r
175 IN UINTN NumberOfBytes\r
176)\r
177{\r
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
187 while ((NumberOfBytes--) != 0) {\r
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
226}\r
227\r
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
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
447 return RETURN_INVALID_PARAMETER;\r
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
461 return RETURN_INVALID_PARAMETER;\r
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
473 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
474\r
475 //\r
476 // Configure baud rate\r
477 //\r
478 IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8) (Divisor >> 8));\r
479 IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8) (Divisor & 0xff));\r
480\r
481 //\r
482 // Switch back to bank 0\r
483 //\r
484 OutputData = (UINT8) ((gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData);\r
485 IoWrite8 (gUartBase + LCR_OFFSET, OutputData);\r
486\r
487 return RETURN_SUCCESS;\r
488}\r
489\r