1 /** @file 2 UART Serial Port library functions 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 <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 successfuly 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 ((UINTN) (gUartBase + LCR_OFFSET), OutputData); 95 96 // 97 // Configure baud rate 98 // 99 IoWrite8 ((UINTN) (gUartBase + BAUD_HIGH_OFFSET), (UINT8) (Divisor >> 8)); 100 IoWrite8 ((UINTN) (gUartBase + BAUD_LOW_OFFSET), (UINT8) (Divisor & 0xff)); 101 102 // 103 // Switch back to bank 0 104 // 105 OutputData = (UINT8) ((~DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data); 106 IoWrite8 ((UINTN) (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 ((UINTN) (gUartBase + LCR_OFFSET), OutputData); 474 475 // 476 // Configure baud rate 477 // 478 IoWrite8 ((UINTN) (gUartBase + BAUD_HIGH_OFFSET), (UINT8) (Divisor >> 8)); 479 IoWrite8 ((UINTN) (gUartBase + BAUD_LOW_OFFSET), (UINT8) (Divisor & 0xff)); 480 481 // 482 // Switch back to bank 0 483 // 484 OutputData = (UINT8) ((~DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData); 485 IoWrite8 ((UINTN) (gUartBase + LCR_OFFSET), OutputData); 486 487 return RETURN_SUCCESS; 488 } 489 490