Serial.c revision ea2d90867ac938e89c4bae0d1c7308940af00784
1/**@file 2 Serial driver for standard UARTS on an ISA bus. 3 4 Copyright (c) 2006 - 2007, Intel Corporation<BR> 5 All rights reserved. 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 "Serial.h" 16 17// 18// ISA Serial Driver Global Variables 19// 20EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = { 21 SerialControllerDriverSupported, 22 SerialControllerDriverStart, 23 SerialControllerDriverStop, 24 0xa, 25 NULL, 26 NULL 27}; 28 29 30SERIAL_DEV gSerialDevTempate = { 31 SERIAL_DEV_SIGNATURE, 32 NULL, 33 { // SerialIo 34 SERIAL_IO_INTERFACE_REVISION, 35 IsaSerialReset, 36 IsaSerialSetAttributes, 37 IsaSerialSetControl, 38 IsaSerialGetControl, 39 IsaSerialWrite, 40 IsaSerialRead, 41 NULL 42 }, 43 { // SerialMode 44 SERIAL_PORT_DEFAULT_CONTROL_MASK, 45 SERIAL_PORT_DEFAULT_TIMEOUT, 46 FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate 47 SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH, 48 FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits 49 FixedPcdGet8 (PcdUartDefaultParity), // Parity 50 FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits 51 }, 52 NULL, 53 NULL, 54 { // UartDevicePath 55 { 56 MESSAGING_DEVICE_PATH, 57 MSG_UART_DP, 58 { 59 (UINT8) (sizeof (UART_DEVICE_PATH)), 60 (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8) 61 } 62 }, 63 0, 64 FixedPcdGet64 (PcdUartDefaultBaudRate), 65 FixedPcdGet8 (PcdUartDefaultDataBits), 66 FixedPcdGet8 (PcdUartDefaultParity), 67 FixedPcdGet8 (PcdUartDefaultStopBits) 68 }, 69 NULL, 70 0, //BaseAddress 71 { 72 0, 73 0, 74 SERIAL_MAX_BUFFER_SIZE, 75 { 0 } 76 }, 77 { 78 0, 79 0, 80 SERIAL_MAX_BUFFER_SIZE, 81 { 0 } 82 }, 83 FALSE, 84 FALSE, 85 UART16550A, 86 NULL 87}; 88 89/** 90 The user Entry Point for module IsaSerial. The user code starts with this function. 91 92 @param[in] ImageHandle The firmware allocated handle for the EFI image. 93 @param[in] SystemTable A pointer to the EFI System Table. 94 95 @retval EFI_SUCCESS The entry point is executed successfully. 96 @retval other Some error occurs when executing this entry point. 97 98**/ 99EFI_STATUS 100EFIAPI 101InitializeIsaSerial ( 102 IN EFI_HANDLE ImageHandle, 103 IN EFI_SYSTEM_TABLE *SystemTable 104 ) 105{ 106 EFI_STATUS Status; 107 108 // 109 // Install driver model protocol(s). 110 // 111 Status = EfiLibInstallDriverBindingComponentName2 ( 112 ImageHandle, 113 SystemTable, 114 &gSerialControllerDriver, 115 ImageHandle, 116 &gIsaSerialComponentName, 117 &gIsaSerialComponentName2 118 ); 119 ASSERT_EFI_ERROR (Status); 120 121 122 return Status; 123} 124 125/** 126 Check to see if this driver supports the given controller 127 128 @param This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 129 @param Controller - The handle of the controller to test. 130 @param RemainingDevicePath - A pointer to the remaining portion of a device path. 131 132 @return EFI_SUCCESS - This driver can support the given controller 133 134**/ 135EFI_STATUS 136EFIAPI 137SerialControllerDriverSupported ( 138 IN EFI_DRIVER_BINDING_PROTOCOL *This, 139 IN EFI_HANDLE Controller, 140 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 141 ) 142 143{ 144 EFI_STATUS Status; 145 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 146 EFI_ISA_IO_PROTOCOL *IsaIo; 147 UART_DEVICE_PATH UartNode; 148 149 // 150 // Ignore the RemainingDevicePath 151 // 152 // 153 // Open the IO Abstraction(s) needed to perform the supported test 154 // 155 Status = gBS->OpenProtocol ( 156 Controller, 157 &gEfiDevicePathProtocolGuid, 158 (VOID **) &ParentDevicePath, 159 This->DriverBindingHandle, 160 Controller, 161 EFI_OPEN_PROTOCOL_BY_DRIVER 162 ); 163 if (Status == EFI_ALREADY_STARTED) { 164 return EFI_SUCCESS; 165 } 166 167 if (EFI_ERROR (Status)) { 168 return Status; 169 } 170 171 gBS->CloseProtocol ( 172 Controller, 173 &gEfiDevicePathProtocolGuid, 174 This->DriverBindingHandle, 175 Controller 176 ); 177 178 Status = gBS->OpenProtocol ( 179 Controller, 180 &gEfiIsaIoProtocolGuid, 181 (VOID **) &IsaIo, 182 This->DriverBindingHandle, 183 Controller, 184 EFI_OPEN_PROTOCOL_BY_DRIVER 185 ); 186 187 if (Status == EFI_ALREADY_STARTED) { 188 return EFI_SUCCESS; 189 } 190 191 if (EFI_ERROR (Status)) { 192 return Status; 193 } 194 // 195 // Use the ISA I/O Protocol to see if Controller is standard ISA UART that 196 // can be managed by this driver. 197 // 198 Status = EFI_SUCCESS; 199 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) { 200 Status = EFI_UNSUPPORTED; 201 goto Error; 202 } 203 // 204 // Make sure RemainingDevicePath is valid 205 // 206 if (RemainingDevicePath != NULL) { 207 Status = EFI_UNSUPPORTED; 208 CopyMem ( 209 &UartNode, 210 (UART_DEVICE_PATH *) RemainingDevicePath, 211 sizeof (UART_DEVICE_PATH) 212 ); 213 if (UartNode.Header.Type != MESSAGING_DEVICE_PATH || 214 UartNode.Header.SubType != MSG_UART_DP || 215 sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &UartNode) 216 ) { 217 goto Error; 218 } 219 220 if (UartNode.BaudRate > SERIAL_PORT_MAX_BAUD_RATE) { 221 goto Error; 222 } 223 224 if (UartNode.Parity < NoParity || UartNode.Parity > SpaceParity) { 225 goto Error; 226 } 227 228 if (UartNode.DataBits < 5 || UartNode.DataBits > 8) { 229 goto Error; 230 } 231 232 if (UartNode.StopBits < OneStopBit || UartNode.StopBits > TwoStopBits) { 233 goto Error; 234 } 235 236 if ((UartNode.DataBits == 5) && (UartNode.StopBits == TwoStopBits)) { 237 goto Error; 238 } 239 240 if ((UartNode.DataBits >= 6) && (UartNode.DataBits <= 8) && (UartNode.StopBits == OneFiveStopBits)) { 241 goto Error; 242 } 243 244 Status = EFI_SUCCESS; 245 } 246 247Error: 248 // 249 // Close the I/O Abstraction(s) used to perform the supported test 250 // 251 gBS->CloseProtocol ( 252 Controller, 253 &gEfiIsaIoProtocolGuid, 254 This->DriverBindingHandle, 255 Controller 256 ); 257 258 return Status; 259} 260 261/** 262 Start to management the controller passed in 263 264 @param This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 265 @param Controller - The handle of the controller to test. 266 @param RemainingDevicePath - A pointer to the remaining portion of a device path. 267 268 @return EFI_SUCCESS - Driver is started successfully 269 270**/ 271EFI_STATUS 272EFIAPI 273SerialControllerDriverStart ( 274 IN EFI_DRIVER_BINDING_PROTOCOL *This, 275 IN EFI_HANDLE Controller, 276 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 277 ) 278 279{ 280 EFI_STATUS Status; 281 EFI_ISA_IO_PROTOCOL *IsaIo; 282 SERIAL_DEV *SerialDevice; 283 UINTN Index; 284 UART_DEVICE_PATH Node; 285 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 286 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; 287 UINTN EntryCount; 288 EFI_SERIAL_IO_PROTOCOL *SerialIo; 289 290 SerialDevice = NULL; 291 // 292 // Get the Parent Device Path 293 // 294 Status = gBS->OpenProtocol ( 295 Controller, 296 &gEfiDevicePathProtocolGuid, 297 (VOID **) &ParentDevicePath, 298 This->DriverBindingHandle, 299 Controller, 300 EFI_OPEN_PROTOCOL_BY_DRIVER 301 ); 302 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 303 return Status; 304 } 305 // 306 // Report status code enable the serial 307 // 308 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 309 EFI_PROGRESS_CODE, 310 EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT, 311 ParentDevicePath 312 ); 313 314 // 315 // Grab the IO abstraction we need to get any work done 316 // 317 Status = gBS->OpenProtocol ( 318 Controller, 319 &gEfiIsaIoProtocolGuid, 320 (VOID **) &IsaIo, 321 This->DriverBindingHandle, 322 Controller, 323 EFI_OPEN_PROTOCOL_BY_DRIVER 324 ); 325 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 326 goto Error; 327 } 328 329 if (Status == EFI_ALREADY_STARTED) { 330 331 if (RemainingDevicePath == NULL) { 332 return EFI_SUCCESS; 333 } 334 // 335 // Make sure a child handle does not already exist. This driver can only 336 // produce one child per serial port. 337 // 338 Status = gBS->OpenProtocolInformation ( 339 Controller, 340 &gEfiIsaIoProtocolGuid, 341 &OpenInfoBuffer, 342 &EntryCount 343 ); 344 if (EFI_ERROR (Status)) { 345 return Status; 346 } 347 348 Status = EFI_ALREADY_STARTED; 349 for (Index = 0; Index < EntryCount; Index++) { 350 if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { 351 Status = gBS->OpenProtocol ( 352 OpenInfoBuffer[Index].ControllerHandle, 353 &gEfiSerialIoProtocolGuid, 354 (VOID **) &SerialIo, 355 This->DriverBindingHandle, 356 Controller, 357 EFI_OPEN_PROTOCOL_GET_PROTOCOL 358 ); 359 if (!EFI_ERROR (Status)) { 360 CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH)); 361 Status = SerialIo->SetAttributes ( 362 SerialIo, 363 Node.BaudRate, 364 SerialIo->Mode->ReceiveFifoDepth, 365 SerialIo->Mode->Timeout, 366 (EFI_PARITY_TYPE) Node.Parity, 367 Node.DataBits, 368 (EFI_STOP_BITS_TYPE) Node.StopBits 369 ); 370 } 371 break; 372 } 373 } 374 375 gBS->FreePool (OpenInfoBuffer); 376 return Status; 377 } 378 // 379 // Initialize the serial device instance 380 // 381 SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTempate); 382 if (SerialDevice == NULL) { 383 Status = EFI_OUT_OF_RESOURCES; 384 goto Error; 385 } 386 387 SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode); 388 SerialDevice->IsaIo = IsaIo; 389 SerialDevice->ParentDevicePath = ParentDevicePath; 390 391 ADD_SERIAL_NAME (SerialDevice, IsaIo); 392 393 for (Index = 0; SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) { 394 if (SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) { 395 SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange; 396 } 397 } 398 // 399 // Report status code the serial present 400 // 401 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 402 EFI_PROGRESS_CODE, 403 EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT, 404 ParentDevicePath 405 ); 406 407 if (!IsaSerialPortPresent (SerialDevice)) { 408 Status = EFI_DEVICE_ERROR; 409 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 410 EFI_ERROR_CODE, 411 EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT, 412 ParentDevicePath 413 ); 414 goto Error; 415 } 416 417 if (RemainingDevicePath != NULL) { 418 // 419 // Match the configuration of the RemainingDevicePath. IsHandleSupported() 420 // already checked to make sure the RemainingDevicePath contains settings 421 // that we can support. 422 // 423 CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH)); 424 } else { 425 // 426 // Use the values from the gSerialDevTempate as no remaining device path was 427 // passed in. 428 // 429 } 430 // 431 // Build the device path by appending the UART node to the ParentDevicePath 432 // from the WinNtIo handle. The Uart setings are zero here, since 433 // SetAttribute() will update them to match the current setings. 434 // 435 SerialDevice->DevicePath = AppendDevicePathNode ( 436 ParentDevicePath, 437 (EFI_DEVICE_PATH_PROTOCOL *)&SerialDevice->UartDevicePath 438 ); 439 if (SerialDevice->DevicePath == NULL) { 440 Status = EFI_DEVICE_ERROR; 441 goto Error; 442 } 443 444 // 445 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults. 446 // 447 SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate; 448 SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits; 449 SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity; 450 SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits; 451 452 // 453 // Issue a reset to initialize the COM port 454 // 455 Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo); 456 if (EFI_ERROR (Status)) { 457 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 458 EFI_ERROR_CODE, 459 EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 460 ParentDevicePath 461 ); 462 goto Error; 463 } 464 // 465 // Install protocol interfaces for the serial device. 466 // 467 Status = gBS->InstallMultipleProtocolInterfaces ( 468 &SerialDevice->Handle, 469 &gEfiDevicePathProtocolGuid, 470 SerialDevice->DevicePath, 471 &gEfiSerialIoProtocolGuid, 472 &SerialDevice->SerialIo, 473 NULL 474 ); 475 if (EFI_ERROR (Status)) { 476 goto Error; 477 } 478 // 479 // Open For Child Device 480 // 481 Status = gBS->OpenProtocol ( 482 Controller, 483 &gEfiIsaIoProtocolGuid, 484 (VOID **) &IsaIo, 485 This->DriverBindingHandle, 486 SerialDevice->Handle, 487 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 488 ); 489 490Error: 491 if (EFI_ERROR (Status)) { 492 gBS->CloseProtocol ( 493 Controller, 494 &gEfiDevicePathProtocolGuid, 495 This->DriverBindingHandle, 496 Controller 497 ); 498 gBS->CloseProtocol ( 499 Controller, 500 &gEfiIsaIoProtocolGuid, 501 This->DriverBindingHandle, 502 Controller 503 ); 504 if (SerialDevice) { 505 if (SerialDevice->DevicePath) { 506 gBS->FreePool (SerialDevice->DevicePath); 507 } 508 509 FreeUnicodeStringTable (SerialDevice->ControllerNameTable); 510 gBS->FreePool (SerialDevice); 511 } 512 } 513 514 return Status; 515} 516 517/** 518 Disconnect this driver with the controller, uninstall related protocol instance 519 520 @param This - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 521 @param Controller - The handle of the controller to test. 522 @param NumberOfChildren - Number of child device. 523 @param ChildHandleBuffer - A pointer to the remaining portion of a device path. 524 525 @retval EFI_SUCCESS - Operation successfully 526 @retval EFI_DEVICE_ERROR - Cannot stop the driver successfully 527 528**/ 529EFI_STATUS 530EFIAPI 531SerialControllerDriverStop ( 532 IN EFI_DRIVER_BINDING_PROTOCOL *This, 533 IN EFI_HANDLE Controller, 534 IN UINTN NumberOfChildren, 535 IN EFI_HANDLE *ChildHandleBuffer 536 ) 537 538{ 539 EFI_STATUS Status; 540 UINTN Index; 541 BOOLEAN AllChildrenStopped; 542 EFI_SERIAL_IO_PROTOCOL *SerialIo; 543 SERIAL_DEV *SerialDevice; 544 EFI_ISA_IO_PROTOCOL *IsaIo; 545 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 546 547 Status = gBS->HandleProtocol ( 548 Controller, 549 &gEfiDevicePathProtocolGuid, 550 (VOID **) &DevicePath 551 ); 552 553 // 554 // Report the status code disable the serial 555 // 556 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 557 EFI_PROGRESS_CODE, 558 EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT, 559 DevicePath 560 ); 561 562 // 563 // Complete all outstanding transactions to Controller. 564 // Don't allow any new transaction to Controller to be started. 565 // 566 if (NumberOfChildren == 0) { 567 // 568 // Close the bus driver 569 // 570 Status = gBS->CloseProtocol ( 571 Controller, 572 &gEfiIsaIoProtocolGuid, 573 This->DriverBindingHandle, 574 Controller 575 ); 576 577 Status = gBS->CloseProtocol ( 578 Controller, 579 &gEfiDevicePathProtocolGuid, 580 This->DriverBindingHandle, 581 Controller 582 ); 583 return Status; 584 } 585 586 AllChildrenStopped = TRUE; 587 588 for (Index = 0; Index < NumberOfChildren; Index++) { 589 590 Status = gBS->OpenProtocol ( 591 ChildHandleBuffer[Index], 592 &gEfiSerialIoProtocolGuid, 593 (VOID **) &SerialIo, 594 This->DriverBindingHandle, 595 Controller, 596 EFI_OPEN_PROTOCOL_GET_PROTOCOL 597 ); 598 if (!EFI_ERROR (Status)) { 599 600 SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo); 601 602 Status = gBS->CloseProtocol ( 603 Controller, 604 &gEfiIsaIoProtocolGuid, 605 This->DriverBindingHandle, 606 ChildHandleBuffer[Index] 607 ); 608 609 Status = gBS->UninstallMultipleProtocolInterfaces ( 610 ChildHandleBuffer[Index], 611 &gEfiDevicePathProtocolGuid, 612 SerialDevice->DevicePath, 613 &gEfiSerialIoProtocolGuid, 614 &SerialDevice->SerialIo, 615 NULL 616 ); 617 if (EFI_ERROR (Status)) { 618 gBS->OpenProtocol ( 619 Controller, 620 &gEfiIsaIoProtocolGuid, 621 (VOID **) &IsaIo, 622 This->DriverBindingHandle, 623 ChildHandleBuffer[Index], 624 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 625 ); 626 } else { 627 if (SerialDevice->DevicePath) { 628 gBS->FreePool (SerialDevice->DevicePath); 629 } 630 631 FreeUnicodeStringTable (SerialDevice->ControllerNameTable); 632 gBS->FreePool (SerialDevice); 633 } 634 } 635 636 if (EFI_ERROR (Status)) { 637 AllChildrenStopped = FALSE; 638 } 639 } 640 641 if (!AllChildrenStopped) { 642 return EFI_DEVICE_ERROR; 643 } 644 645 return EFI_SUCCESS; 646} 647 648/** 649 Detect whether specific FIFO is full or not 650 651 @param Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO 652 653 @return whether specific FIFO is full or not 654 655**/ 656BOOLEAN 657IsaSerialFifoFull ( 658 IN SERIAL_DEV_FIFO *Fifo 659 ) 660 661{ 662 if (Fifo->Surplus == 0) { 663 return TRUE; 664 } 665 666 return FALSE; 667} 668 669/** 670 Detect whether specific FIFO is empty or not 671 672 673 @param Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO 674 675 @return whether specific FIFO is empty or not 676 677**/ 678BOOLEAN 679IsaSerialFifoEmpty ( 680 IN SERIAL_DEV_FIFO *Fifo 681 ) 682 683{ 684 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) { 685 return TRUE; 686 } 687 688 return FALSE; 689} 690 691/** 692 Add data to specific FIFO 693 694 @param Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO 695 @param Data - the data added to FIFO 696 697 @retval EFI_SUCCESS - Add data to specific FIFO successfully 698 @retval EFI_OUT_OF_RESOURCE - Failed to add data because FIFO is already full 699 700**/ 701EFI_STATUS 702IsaSerialFifoAdd ( 703 IN SERIAL_DEV_FIFO *Fifo, 704 IN UINT8 Data 705 ) 706 707{ 708 // 709 // if FIFO full can not add data 710 // 711 if (IsaSerialFifoFull (Fifo)) { 712 return EFI_OUT_OF_RESOURCES; 713 } 714 // 715 // FIFO is not full can add data 716 // 717 Fifo->Data[Fifo->Last] = Data; 718 Fifo->Surplus--; 719 Fifo->Last++; 720 if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) { 721 Fifo->Last = 0; 722 } 723 724 return EFI_SUCCESS; 725} 726 727/** 728 Remove data from specific FIFO 729 730 @param Fifo - A pointer to the Data Structure SERIAL_DEV_FIFO 731 @param Data - the data removed from FIFO 732 733 @retval EFI_SUCCESS - Remove data from specific FIFO successfully 734 @retval EFI_OUT_OF_RESOURCE - Failed to remove data because FIFO is empty 735 736**/ 737EFI_STATUS 738IsaSerialFifoRemove ( 739 IN SERIAL_DEV_FIFO *Fifo, 740 OUT UINT8 *Data 741 ) 742 743{ 744 // 745 // if FIFO is empty, no data can remove 746 // 747 if (IsaSerialFifoEmpty (Fifo)) { 748 return EFI_OUT_OF_RESOURCES; 749 } 750 // 751 // FIFO is not empty, can remove data 752 // 753 *Data = Fifo->Data[Fifo->First]; 754 Fifo->Surplus++; 755 Fifo->First++; 756 if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) { 757 Fifo->First = 0; 758 } 759 760 return EFI_SUCCESS; 761} 762 763/** 764 Reads and writes all avaliable data. 765 766 @param SerialDevice - The device to flush 767 768 @retval EFI_SUCCESS - Data was read/written successfully. 769 @retval EFI_OUT_OF_RESOURCE - Failed because software receive FIFO is full. Note, when 770 this happens, pending writes are not done. 771 772**/ 773EFI_STATUS 774IsaSerialReceiveTransmit ( 775 IN SERIAL_DEV *SerialDevice 776 ) 777 778{ 779 SERIAL_PORT_LSR Lsr; 780 UINT8 Data; 781 BOOLEAN ReceiveFifoFull; 782 SERIAL_PORT_MSR Msr; 783 SERIAL_PORT_MCR Mcr; 784 UINTN TimeOut; 785 786 Data = 0; 787 788 // 789 // Begin the read or write 790 // 791 if (SerialDevice->SoftwareLoopbackEnable) { 792 do { 793 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); 794 if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 795 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); 796 if (ReceiveFifoFull) { 797 return EFI_OUT_OF_RESOURCES; 798 } 799 800 IsaSerialFifoAdd (&SerialDevice->Receive, Data); 801 } 802 } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit)); 803 } else { 804 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); 805 do { 806 Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 807 808 // 809 // Flush incomming data to prevent a an overrun during a long write 810 // 811 if (Lsr.Bits.DR && !ReceiveFifoFull) { 812 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); 813 if (!ReceiveFifoFull) { 814 if (Lsr.Bits.FIFOE || Lsr.Bits.OE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) { 815 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 816 EFI_ERROR_CODE, 817 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 818 SerialDevice->DevicePath 819 ); 820 if (Lsr.Bits.FIFOE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) { 821 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 822 continue; 823 } 824 } 825 // 826 // Make sure the receive data will not be missed, Assert DTR 827 // 828 if (SerialDevice->HardwareFlowControl) { 829 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 830 Mcr.Bits.DTRC &= 0; 831 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 832 } 833 834 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 835 836 // 837 // Deassert DTR 838 // 839 if (SerialDevice->HardwareFlowControl) { 840 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 841 Mcr.Bits.DTRC |= 1; 842 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 843 } 844 845 IsaSerialFifoAdd (&SerialDevice->Receive, Data); 846 847 continue; 848 } else { 849 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 850 EFI_PROGRESS_CODE, 851 EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT, 852 SerialDevice->DevicePath 853 ); 854 } 855 } 856 // 857 // Do the write 858 // 859 if (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 860 // 861 // Make sure the transmit data will not be missed 862 // 863 if (SerialDevice->HardwareFlowControl) { 864 // 865 // Send RTS 866 // 867 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 868 Mcr.Bits.RTS |= 1; 869 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 870 // 871 // Wait for CTS 872 // 873 TimeOut = 0; 874 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 875 while (!Msr.Bits.CTS) { 876 gBS->Stall (TIMEOUT_STALL_INTERVAL); 877 TimeOut++; 878 if (TimeOut > 5) { 879 break; 880 } 881 882 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 883 } 884 885 if (Msr.Bits.CTS) { 886 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); 887 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data); 888 } 889 } 890 // 891 // write the data out 892 // 893 if (!SerialDevice->HardwareFlowControl) { 894 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); 895 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data); 896 } 897 // 898 // Make sure the transmit data will not be missed 899 // 900 if (SerialDevice->HardwareFlowControl) { 901 // 902 // Assert RTS 903 // 904 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 905 Mcr.Bits.RTS &= 0; 906 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 907 } 908 } 909 } while (Lsr.Bits.THRE && !IsaSerialFifoEmpty (&SerialDevice->Transmit)); 910 } 911 912 return EFI_SUCCESS; 913} 914 915// 916// Interface Functions 917// 918/** 919 Reset serial device 920 921 @param This - Pointer to EFI_SERIAL_IO_PROTOCOL 922 923 @retval EFI_SUCCESS - Reset successfully 924 @retval EFI_DEVICE_ERROR - Failed to reset 925 926**/ 927EFI_STATUS 928EFIAPI 929IsaSerialReset ( 930 IN EFI_SERIAL_IO_PROTOCOL *This 931 ) 932{ 933 EFI_STATUS Status; 934 SERIAL_DEV *SerialDevice; 935 SERIAL_PORT_LCR Lcr; 936 SERIAL_PORT_IER Ier; 937 SERIAL_PORT_MCR Mcr; 938 SERIAL_PORT_FCR Fcr; 939 EFI_TPL Tpl; 940 941 SerialDevice = SERIAL_DEV_FROM_THIS (This); 942 943 // 944 // Report the status code reset the serial 945 // 946 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 947 EFI_PROGRESS_CODE, 948 EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT, 949 SerialDevice->DevicePath 950 ); 951 952 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 953 954 // 955 // Make sure DLAB is 0. 956 // 957 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 958 Lcr.Bits.DLAB = 0; 959 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 960 961 // 962 // Turn off all interrupts 963 // 964 Ier.Data = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress); 965 Ier.Bits.RAVIE = 0; 966 Ier.Bits.THEIE = 0; 967 Ier.Bits.RIE = 0; 968 Ier.Bits.MIE = 0; 969 WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data); 970 971 // 972 // Disable the FIFO. 973 // 974 Fcr.Bits.TRFIFOE = 0; 975 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data); 976 977 // 978 // Turn off loopback and disable device interrupt. 979 // 980 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 981 Mcr.Bits.OUT1 = 0; 982 Mcr.Bits.OUT2 = 0; 983 Mcr.Bits.LME = 0; 984 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 985 986 // 987 // Clear the scratch pad register 988 // 989 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0); 990 991 // 992 // Go set the current attributes 993 // 994 Status = This->SetAttributes ( 995 This, 996 This->Mode->BaudRate, 997 This->Mode->ReceiveFifoDepth, 998 This->Mode->Timeout, 999 (EFI_PARITY_TYPE) This->Mode->Parity, 1000 (UINT8) This->Mode->DataBits, 1001 (EFI_STOP_BITS_TYPE) This->Mode->StopBits 1002 ); 1003 1004 if (EFI_ERROR (Status)) { 1005 gBS->RestoreTPL (Tpl); 1006 return EFI_DEVICE_ERROR; 1007 } 1008 // 1009 // Go set the current control bits 1010 // 1011 Status = This->SetControl ( 1012 This, 1013 This->Mode->ControlMask 1014 ); 1015 1016 if (EFI_ERROR (Status)) { 1017 gBS->RestoreTPL (Tpl); 1018 return EFI_DEVICE_ERROR; 1019 } 1020 // 1021 // for 16550A enable FIFO, 16550 disable FIFO 1022 // 1023 Fcr.Bits.TRFIFOE = 1; 1024 Fcr.Bits.RESETRF = 1; 1025 Fcr.Bits.RESETTF = 1; 1026 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data); 1027 1028 // 1029 // Reset the software FIFO 1030 // 1031 SerialDevice->Receive.First = 0; 1032 SerialDevice->Receive.Last = 0; 1033 SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE; 1034 SerialDevice->Transmit.First = 0; 1035 SerialDevice->Transmit.Last = 0; 1036 SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE; 1037 1038 gBS->RestoreTPL (Tpl); 1039 1040 // 1041 // Device reset is complete 1042 // 1043 return EFI_SUCCESS; 1044} 1045 1046/** 1047 Set new attributes to a serial device 1048 1049 @param This - Pointer to EFI_SERIAL_IO_PROTOCOL 1050 @param BaudRate - The baudrate of the serial device 1051 @param ReceiveFifoDepth - The depth of receive FIFO buffer 1052 @param Timeout - The request timeout for a single char 1053 @param Parity - The type of parity used in serial device 1054 @param DataBits - Number of databits used in serial device 1055 @param StopBits - Number of stopbits used in serial device 1056 1057 @retval EFI_SUCCESS - The new attributes were set 1058 @retval EFI_INVALID_PARAMETERS - One or more attributes have an unsupported value 1059 @retval EFI_UNSUPPORTED - Data Bits can not set to 5 or 6 1060 @retval EFI_DEVICE_ERROR - The serial device is not functioning correctly (no return) 1061 1062**/ 1063EFI_STATUS 1064EFIAPI 1065IsaSerialSetAttributes ( 1066 IN EFI_SERIAL_IO_PROTOCOL *This, 1067 IN UINT64 BaudRate, 1068 IN UINT32 ReceiveFifoDepth, 1069 IN UINT32 Timeout, 1070 IN EFI_PARITY_TYPE Parity, 1071 IN UINT8 DataBits, 1072 IN EFI_STOP_BITS_TYPE StopBits 1073 ) 1074{ 1075 EFI_STATUS Status; 1076 SERIAL_DEV *SerialDevice; 1077 UINT32 Divisor; 1078 UINT32 Remained; 1079 SERIAL_PORT_LCR Lcr; 1080 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 1081 EFI_TPL Tpl; 1082 1083 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1084 1085 // 1086 // Check for default settings and fill in actual values. 1087 // 1088 if (BaudRate == 0) { 1089 BaudRate = FixedPcdGet64 (PcdUartDefaultBaudRate); 1090 } 1091 1092 if (ReceiveFifoDepth == 0) { 1093 ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH; 1094 } 1095 1096 if (Timeout == 0) { 1097 Timeout = SERIAL_PORT_DEFAULT_TIMEOUT; 1098 } 1099 1100 if (Parity == DefaultParity) { 1101 Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity); 1102 } 1103 1104 if (DataBits == 0) { 1105 DataBits = FixedPcdGet8 (PcdUartDefaultDataBits); 1106 } 1107 1108 if (StopBits == DefaultStopBits) { 1109 StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits); 1110 } 1111 // 1112 // 5 and 6 data bits can not be verified on a 16550A UART 1113 // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings. 1114 // 1115 if ((DataBits == 5) || (DataBits == 6)) { 1116 return EFI_INVALID_PARAMETER; 1117 } 1118 // 1119 // Make sure all parameters are valid 1120 // 1121 if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) { 1122 return EFI_INVALID_PARAMETER; 1123 } 1124 // 1125 // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200, 1126 // 38400,57600,115200 1127 // 1128 if (BaudRate < 75) { 1129 BaudRate = 50; 1130 } else if (BaudRate < 110) { 1131 BaudRate = 75; 1132 } else if (BaudRate < 134) { 1133 BaudRate = 110; 1134 } else if (BaudRate < 150) { 1135 BaudRate = 134; 1136 } else if (BaudRate < 300) { 1137 BaudRate = 150; 1138 } else if (BaudRate < 600) { 1139 BaudRate = 300; 1140 } else if (BaudRate < 1200) { 1141 BaudRate = 600; 1142 } else if (BaudRate < 1800) { 1143 BaudRate = 1200; 1144 } else if (BaudRate < 2000) { 1145 BaudRate = 1800; 1146 } else if (BaudRate < 2400) { 1147 BaudRate = 2000; 1148 } else if (BaudRate < 3600) { 1149 BaudRate = 2400; 1150 } else if (BaudRate < 4800) { 1151 BaudRate = 3600; 1152 } else if (BaudRate < 7200) { 1153 BaudRate = 4800; 1154 } else if (BaudRate < 9600) { 1155 BaudRate = 7200; 1156 } else if (BaudRate < 19200) { 1157 BaudRate = 9600; 1158 } else if (BaudRate < 38400) { 1159 BaudRate = 19200; 1160 } else if (BaudRate < 57600) { 1161 BaudRate = 38400; 1162 } else if (BaudRate < 115200) { 1163 BaudRate = 57600; 1164 } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) { 1165 BaudRate = 115200; 1166 } 1167 1168 if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) { 1169 return EFI_INVALID_PARAMETER; 1170 } 1171 1172 if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) { 1173 return EFI_INVALID_PARAMETER; 1174 } 1175 1176 if ((Parity < NoParity) || (Parity > SpaceParity)) { 1177 return EFI_INVALID_PARAMETER; 1178 } 1179 1180 if ((DataBits < 5) || (DataBits > 8)) { 1181 return EFI_INVALID_PARAMETER; 1182 } 1183 1184 if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) { 1185 return EFI_INVALID_PARAMETER; 1186 } 1187 // 1188 // for DataBits = 5, StopBits can not set TwoStopBits 1189 // 1190 // if ((DataBits == 5) && (StopBits == TwoStopBits)) { 1191 // return EFI_INVALID_PARAMETER; 1192 // } 1193 // 1194 // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits 1195 // 1196 if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) { 1197 return EFI_INVALID_PARAMETER; 1198 } 1199 1200 // 1201 // Compute divisor use to program the baud rate using a round determination 1202 // 1203 Divisor = (UINT32) DivU64x32Remainder ( 1204 SERIAL_PORT_INPUT_CLOCK, 1205 ((UINT32) BaudRate * 16), 1206 &Remained 1207 ); 1208 if (Remained) { 1209 Divisor += 1; 1210 } 1211 1212 if ((Divisor == 0) || (Divisor & 0xffff0000)) { 1213 return EFI_INVALID_PARAMETER; 1214 } 1215 1216 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1217 1218 // 1219 // Compute the actual baud rate that the serial port will be programmed for. 1220 // 1221 BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16; 1222 1223 // 1224 // Put serial port on Divisor Latch Mode 1225 // 1226 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1227 Lcr.Bits.DLAB = 1; 1228 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 1229 1230 // 1231 // Write the divisor to the serial port 1232 // 1233 WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff)); 1234 WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff)); 1235 1236 // 1237 // Put serial port back in normal mode and set remaining attributes. 1238 // 1239 Lcr.Bits.DLAB = 0; 1240 1241 switch (Parity) { 1242 case NoParity: 1243 Lcr.Bits.PAREN = 0; 1244 Lcr.Bits.EVENPAR = 0; 1245 Lcr.Bits.STICPAR = 0; 1246 break; 1247 1248 case EvenParity: 1249 Lcr.Bits.PAREN = 1; 1250 Lcr.Bits.EVENPAR = 1; 1251 Lcr.Bits.STICPAR = 0; 1252 break; 1253 1254 case OddParity: 1255 Lcr.Bits.PAREN = 1; 1256 Lcr.Bits.EVENPAR = 0; 1257 Lcr.Bits.STICPAR = 0; 1258 break; 1259 1260 case SpaceParity: 1261 Lcr.Bits.PAREN = 1; 1262 Lcr.Bits.EVENPAR = 1; 1263 Lcr.Bits.STICPAR = 1; 1264 break; 1265 1266 case MarkParity: 1267 Lcr.Bits.PAREN = 1; 1268 Lcr.Bits.EVENPAR = 0; 1269 Lcr.Bits.STICPAR = 1; 1270 break; 1271 1272 default: 1273 break; 1274 } 1275 1276 switch (StopBits) { 1277 case OneStopBit: 1278 Lcr.Bits.STOPB = 0; 1279 break; 1280 1281 case OneFiveStopBits: 1282 case TwoStopBits: 1283 Lcr.Bits.STOPB = 1; 1284 break; 1285 1286 default: 1287 break; 1288 } 1289 // 1290 // DataBits 1291 // 1292 Lcr.Bits.SERIALDB = (UINT8) ((DataBits - 5) & 0x03); 1293 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 1294 1295 // 1296 // Set the Serial I/O mode 1297 // 1298 This->Mode->BaudRate = BaudRate; 1299 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; 1300 This->Mode->Timeout = Timeout; 1301 This->Mode->Parity = Parity; 1302 This->Mode->DataBits = DataBits; 1303 This->Mode->StopBits = StopBits; 1304 1305 // 1306 // See if Device Path Node has actually changed 1307 // 1308 if (SerialDevice->UartDevicePath.BaudRate == BaudRate && 1309 SerialDevice->UartDevicePath.DataBits == DataBits && 1310 SerialDevice->UartDevicePath.Parity == Parity && 1311 SerialDevice->UartDevicePath.StopBits == StopBits 1312 ) { 1313 gBS->RestoreTPL (Tpl); 1314 return EFI_SUCCESS; 1315 } 1316 // 1317 // Update the device path 1318 // 1319 SerialDevice->UartDevicePath.BaudRate = BaudRate; 1320 SerialDevice->UartDevicePath.DataBits = DataBits; 1321 SerialDevice->UartDevicePath.Parity = (UINT8) Parity; 1322 SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits; 1323 1324 NewDevicePath = AppendDevicePathNode ( 1325 SerialDevice->ParentDevicePath, 1326 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath 1327 ); 1328 if (NewDevicePath == NULL) { 1329 gBS->RestoreTPL (Tpl); 1330 return EFI_DEVICE_ERROR; 1331 } 1332 1333 if (SerialDevice->Handle != NULL) { 1334 Status = gBS->ReinstallProtocolInterface ( 1335 SerialDevice->Handle, 1336 &gEfiDevicePathProtocolGuid, 1337 SerialDevice->DevicePath, 1338 NewDevicePath 1339 ); 1340 if (EFI_ERROR (Status)) { 1341 gBS->RestoreTPL (Tpl); 1342 return Status; 1343 } 1344 } 1345 1346 if (SerialDevice->DevicePath) { 1347 gBS->FreePool (SerialDevice->DevicePath); 1348 } 1349 1350 SerialDevice->DevicePath = NewDevicePath; 1351 1352 gBS->RestoreTPL (Tpl); 1353 1354 return EFI_SUCCESS; 1355} 1356 1357/** 1358 Set Control Bits 1359 1360 @param This - Pointer to EFI_SERIAL_IO_PROTOCOL 1361 @param Control - Control bits that can be settable 1362 1363 @retval EFI_SUCCESS - New Control bits were set successfully 1364 @retval EFI_UNSUPPORTED - The Control bits wanted to set are not supported 1365 1366**/ 1367EFI_STATUS 1368EFIAPI 1369IsaSerialSetControl ( 1370 IN EFI_SERIAL_IO_PROTOCOL *This, 1371 IN UINT32 Control 1372 ) 1373{ 1374 SERIAL_DEV *SerialDevice; 1375 SERIAL_PORT_MCR Mcr; 1376 EFI_TPL Tpl; 1377 1378 // 1379 // The control bits that can be set are : 1380 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO 1381 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO 1382 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW 1383 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW 1384 // 1385 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1386 1387 // 1388 // first determine the parameter is invalid 1389 // 1390 if (Control & 0xffff8ffc) { 1391 return EFI_UNSUPPORTED; 1392 } 1393 1394 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1395 1396 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1397 Mcr.Bits.DTRC = 0; 1398 Mcr.Bits.RTS = 0; 1399 Mcr.Bits.LME = 0; 1400 SerialDevice->SoftwareLoopbackEnable = FALSE; 1401 SerialDevice->HardwareFlowControl = FALSE; 1402 1403 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) { 1404 Mcr.Bits.DTRC = 1; 1405 } 1406 1407 if (Control & EFI_SERIAL_REQUEST_TO_SEND) { 1408 Mcr.Bits.RTS = 1; 1409 } 1410 1411 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) { 1412 Mcr.Bits.LME = 1; 1413 } 1414 1415 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { 1416 SerialDevice->HardwareFlowControl = TRUE; 1417 } 1418 1419 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 1420 1421 if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) { 1422 SerialDevice->SoftwareLoopbackEnable = TRUE; 1423 } 1424 1425 gBS->RestoreTPL (Tpl); 1426 1427 return EFI_SUCCESS; 1428} 1429 1430/** 1431 Get ControlBits 1432 1433 @param This - Pointer to EFI_SERIAL_IO_PROTOCOL 1434 @param Control - Control signals of the serial device 1435 1436 @retval EFI_SUCCESS - Get Control signals successfully 1437 1438**/ 1439EFI_STATUS 1440EFIAPI 1441IsaSerialGetControl ( 1442 IN EFI_SERIAL_IO_PROTOCOL *This, 1443 OUT UINT32 *Control 1444 ) 1445{ 1446 SERIAL_DEV *SerialDevice; 1447 SERIAL_PORT_MSR Msr; 1448 SERIAL_PORT_MCR Mcr; 1449 EFI_TPL Tpl; 1450 1451 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1452 1453 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1454 1455 *Control = 0; 1456 1457 // 1458 // Read the Modem Status Register 1459 // 1460 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1461 1462 if (Msr.Bits.CTS) { 1463 *Control |= EFI_SERIAL_CLEAR_TO_SEND; 1464 } 1465 1466 if (Msr.Bits.DSR) { 1467 *Control |= EFI_SERIAL_DATA_SET_READY; 1468 } 1469 1470 if (Msr.Bits.RI) { 1471 *Control |= EFI_SERIAL_RING_INDICATE; 1472 } 1473 1474 if (Msr.Bits.DCD) { 1475 *Control |= EFI_SERIAL_CARRIER_DETECT; 1476 } 1477 // 1478 // Read the Modem Control Register 1479 // 1480 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1481 1482 if (Mcr.Bits.DTRC) { 1483 *Control |= EFI_SERIAL_DATA_TERMINAL_READY; 1484 } 1485 1486 if (Mcr.Bits.RTS) { 1487 *Control |= EFI_SERIAL_REQUEST_TO_SEND; 1488 } 1489 1490 if (Mcr.Bits.LME) { 1491 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; 1492 } 1493 1494 if (SerialDevice->HardwareFlowControl) { 1495 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; 1496 } 1497 // 1498 // See if the Transmit FIFO is empty 1499 // 1500 IsaSerialReceiveTransmit (SerialDevice); 1501 1502 if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 1503 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; 1504 } 1505 // 1506 // See if the Receive FIFO is empty. 1507 // 1508 IsaSerialReceiveTransmit (SerialDevice); 1509 1510 if (IsaSerialFifoEmpty (&SerialDevice->Receive)) { 1511 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; 1512 } 1513 1514 if (SerialDevice->SoftwareLoopbackEnable) { 1515 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; 1516 } 1517 1518 gBS->RestoreTPL (Tpl); 1519 1520 return EFI_SUCCESS; 1521} 1522 1523/** 1524 Write the specified number of bytes to serial device 1525 1526 @param This - Pointer to EFI_SERIAL_IO_PROTOCOL 1527 @param BufferSize - On input the size of Buffer, on output the amount of 1528 data actually written 1529 @param Buffer - The buffer of data to write 1530 1531 @retval EFI_SUCCESS - The data were written successfully 1532 @retval EFI_DEVICE_ERROR - The device reported an error 1533 @retval EFI_TIMEOUT - The write operation was stopped due to timeout 1534 1535**/ 1536EFI_STATUS 1537EFIAPI 1538IsaSerialWrite ( 1539 IN EFI_SERIAL_IO_PROTOCOL *This, 1540 IN OUT UINTN *BufferSize, 1541 IN VOID *Buffer 1542 ) 1543{ 1544 SERIAL_DEV *SerialDevice; 1545 UINT8 *CharBuffer; 1546 UINT32 Index; 1547 UINTN Elapsed; 1548 UINTN ActualWrite; 1549 EFI_TPL Tpl; 1550 1551 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1552 Elapsed = 0; 1553 ActualWrite = 0; 1554 1555 if (*BufferSize == 0) { 1556 return EFI_SUCCESS; 1557 } 1558 1559 if (!Buffer) { 1560 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1561 EFI_ERROR_CODE, 1562 EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 1563 SerialDevice->DevicePath 1564 ); 1565 1566 return EFI_DEVICE_ERROR; 1567 } 1568 1569 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1570 1571 CharBuffer = (UINT8 *) Buffer; 1572 1573 for (Index = 0; Index < *BufferSize; Index++) { 1574 IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]); 1575 1576 while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 1577 // 1578 // Unsuccessful write so check if timeout has expired, if not, 1579 // stall for a bit, increment time elapsed, and try again 1580 // 1581 if (Elapsed >= This->Mode->Timeout) { 1582 *BufferSize = ActualWrite; 1583 gBS->RestoreTPL (Tpl); 1584 return EFI_TIMEOUT; 1585 } 1586 1587 gBS->Stall (TIMEOUT_STALL_INTERVAL); 1588 1589 Elapsed += TIMEOUT_STALL_INTERVAL; 1590 } 1591 1592 ActualWrite++; 1593 // 1594 // Successful write so reset timeout 1595 // 1596 Elapsed = 0; 1597 } 1598 1599 gBS->RestoreTPL (Tpl); 1600 1601 return EFI_SUCCESS; 1602} 1603 1604/** 1605 Read the specified number of bytes from serial device 1606 1607 @param This - Pointer to EFI_SERIAL_IO_PROTOCOL 1608 @param BufferSize - On input the size of Buffer, on output the amount of 1609 data returned in buffer 1610 @param Buffer - The buffer to return the data into 1611 1612 @retval EFI_SUCCESS - The data were read successfully 1613 @retval EFI_DEVICE_ERROR - The device reported an error 1614 @retval EFI_TIMEOUT - The read operation was stopped due to timeout 1615 1616**/ 1617EFI_STATUS 1618EFIAPI 1619IsaSerialRead ( 1620 IN EFI_SERIAL_IO_PROTOCOL *This, 1621 IN OUT UINTN *BufferSize, 1622 OUT VOID *Buffer 1623 ) 1624{ 1625 SERIAL_DEV *SerialDevice; 1626 UINT32 Index; 1627 UINT8 *CharBuffer; 1628 UINTN Elapsed; 1629 EFI_STATUS Status; 1630 EFI_TPL Tpl; 1631 1632 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1633 Elapsed = 0; 1634 1635 if (*BufferSize == 0) { 1636 return EFI_SUCCESS; 1637 } 1638 1639 if (!Buffer) { 1640 return EFI_DEVICE_ERROR; 1641 } 1642 1643 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1644 1645 Status = IsaSerialReceiveTransmit (SerialDevice); 1646 1647 if (EFI_ERROR (Status)) { 1648 *BufferSize = 0; 1649 1650 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1651 EFI_ERROR_CODE, 1652 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 1653 SerialDevice->DevicePath 1654 ); 1655 1656 gBS->RestoreTPL (Tpl); 1657 1658 return EFI_DEVICE_ERROR; 1659 } 1660 1661 CharBuffer = (UINT8 *) Buffer; 1662 for (Index = 0; Index < *BufferSize; Index++) { 1663 while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) { 1664 // 1665 // Unsuccessful read so check if timeout has expired, if not, 1666 // stall for a bit, increment time elapsed, and try again 1667 // Need this time out to get conspliter to work. 1668 // 1669 if (Elapsed >= This->Mode->Timeout) { 1670 *BufferSize = Index; 1671 gBS->RestoreTPL (Tpl); 1672 return EFI_TIMEOUT; 1673 } 1674 1675 gBS->Stall (TIMEOUT_STALL_INTERVAL); 1676 Elapsed += TIMEOUT_STALL_INTERVAL; 1677 1678 Status = IsaSerialReceiveTransmit (SerialDevice); 1679 if (Status == EFI_DEVICE_ERROR) { 1680 *BufferSize = Index; 1681 gBS->RestoreTPL (Tpl); 1682 return EFI_DEVICE_ERROR; 1683 } 1684 } 1685 // 1686 // Successful read so reset timeout 1687 // 1688 Elapsed = 0; 1689 } 1690 1691 IsaSerialReceiveTransmit (SerialDevice); 1692 1693 gBS->RestoreTPL (Tpl); 1694 1695 return EFI_SUCCESS; 1696} 1697 1698/** 1699 Use scratchpad register to test if this serial port is present 1700 1701 @param SerialDevice - Pointer to serial device structure 1702 1703 @return if this serial port is present 1704**/ 1705BOOLEAN 1706IsaSerialPortPresent ( 1707 IN SERIAL_DEV *SerialDevice 1708 ) 1709 1710{ 1711 UINT8 Temp; 1712 BOOLEAN Status; 1713 1714 Status = TRUE; 1715 1716 // 1717 // Save SCR reg 1718 // 1719 Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1720 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA); 1721 1722 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) { 1723 Status = FALSE; 1724 } 1725 1726 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55); 1727 1728 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) { 1729 Status = FALSE; 1730 } 1731 // 1732 // Restore SCR 1733 // 1734 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp); 1735 return Status; 1736} 1737 1738/** 1739 Use IsaIo protocol to read serial port 1740 1741 @param IsaIo - Pointer to EFI_ISA_IO_PROTOCOL instance 1742 @param BaseAddress - Serial port register group base address 1743 @param Offset - Offset in register group 1744 1745 @return Data read from serial port 1746 1747**/ 1748UINT8 1749IsaSerialReadPort ( 1750 IN EFI_ISA_IO_PROTOCOL *IsaIo, 1751 IN UINT16 BaseAddress, 1752 IN UINT32 Offset 1753 ) 1754{ 1755 UINT8 Data; 1756 1757 // 1758 // Use IsaIo to access IO 1759 // 1760 IsaIo->Io.Read ( 1761 IsaIo, 1762 EfiIsaIoWidthUint8, 1763 BaseAddress + Offset, 1764 1, 1765 &Data 1766 ); 1767 return Data; 1768} 1769 1770/** 1771 Use IsaIo protocol to write serial port 1772 1773 @param IsaIo - Pointer to EFI_ISA_IO_PROTOCOL instance 1774 @param BaseAddress - Serial port register group base address 1775 @param Offset - Offset in register group 1776 @param Data - data which is to be written to some serial port register 1777 1778**/ 1779VOID 1780IsaSerialWritePort ( 1781 IN EFI_ISA_IO_PROTOCOL *IsaIo, 1782 IN UINT16 BaseAddress, 1783 IN UINT32 Offset, 1784 IN UINT8 Data 1785 ) 1786{ 1787 // 1788 // Use IsaIo to access IO 1789 // 1790 IsaIo->Io.Write ( 1791 IsaIo, 1792 EfiIsaIoWidthUint8, 1793 BaseAddress + Offset, 1794 1, 1795 &Data 1796 ); 1797} 1798 1799