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