Serial.c revision 19bf20e11acd88a02922201f97e6d64edcd16390
1/** @file 2 Serial driver for standard UARTS on an ISA bus. 3 4Copyright (c) 2006 - 2009, Intel Corporation<BR> 5All rights reserved. This program and the accompanying materials 6are licensed and made available under the terms and conditions of the BSD License 7which accompanies this distribution. The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT 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 AddName (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 != NULL) { 505 if (SerialDevice->DevicePath != NULL) { 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 != NULL) { 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 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO 673 674 @return whether specific FIFO is empty or not 675 676**/ 677BOOLEAN 678IsaSerialFifoEmpty ( 679 IN SERIAL_DEV_FIFO *Fifo 680 ) 681 682{ 683 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) { 684 return TRUE; 685 } 686 687 return FALSE; 688} 689 690/** 691 Add data to specific FIFO. 692 693 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO 694 @param Data the data added to FIFO 695 696 @retval EFI_SUCCESS Add data to specific FIFO successfully 697 @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full 698 699**/ 700EFI_STATUS 701IsaSerialFifoAdd ( 702 IN SERIAL_DEV_FIFO *Fifo, 703 IN UINT8 Data 704 ) 705 706{ 707 // 708 // if FIFO full can not add data 709 // 710 if (IsaSerialFifoFull (Fifo)) { 711 return EFI_OUT_OF_RESOURCES; 712 } 713 // 714 // FIFO is not full can add data 715 // 716 Fifo->Data[Fifo->Last] = Data; 717 Fifo->Surplus--; 718 Fifo->Last++; 719 if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) { 720 Fifo->Last = 0; 721 } 722 723 return EFI_SUCCESS; 724} 725 726/** 727 Remove data from specific FIFO. 728 729 @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO 730 @param Data the data removed from FIFO 731 732 @retval EFI_SUCCESS Remove data from specific FIFO successfully 733 @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty 734 735**/ 736EFI_STATUS 737IsaSerialFifoRemove ( 738 IN SERIAL_DEV_FIFO *Fifo, 739 OUT UINT8 *Data 740 ) 741 742{ 743 // 744 // if FIFO is empty, no data can remove 745 // 746 if (IsaSerialFifoEmpty (Fifo)) { 747 return EFI_OUT_OF_RESOURCES; 748 } 749 // 750 // FIFO is not empty, can remove data 751 // 752 *Data = Fifo->Data[Fifo->First]; 753 Fifo->Surplus++; 754 Fifo->First++; 755 if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) { 756 Fifo->First = 0; 757 } 758 759 return EFI_SUCCESS; 760} 761 762/** 763 Reads and writes all avaliable data. 764 765 @param SerialDevice The device to flush 766 767 @retval EFI_SUCCESS Data was read/written successfully. 768 @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when 769 this happens, pending writes are not done. 770 771**/ 772EFI_STATUS 773IsaSerialReceiveTransmit ( 774 IN SERIAL_DEV *SerialDevice 775 ) 776 777{ 778 SERIAL_PORT_LSR Lsr; 779 UINT8 Data; 780 BOOLEAN ReceiveFifoFull; 781 SERIAL_PORT_MSR Msr; 782 SERIAL_PORT_MCR Mcr; 783 UINTN TimeOut; 784 785 Data = 0; 786 787 // 788 // Begin the read or write 789 // 790 if (SerialDevice->SoftwareLoopbackEnable) { 791 do { 792 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); 793 if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 794 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); 795 if (ReceiveFifoFull) { 796 return EFI_OUT_OF_RESOURCES; 797 } 798 799 IsaSerialFifoAdd (&SerialDevice->Receive, Data); 800 } 801 } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit)); 802 } else { 803 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); 804 // 805 // For full handshake flow control, tell the peer to send data 806 // if receive buffer is available. 807 // 808 if (SerialDevice->HardwareFlowControl && 809 !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)&& 810 !ReceiveFifoFull 811 ) { 812 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 813 Mcr.Bits.Rts = 1; 814 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 815 } 816 do { 817 Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 818 819 // 820 // Flush incomming data to prevent a an overrun during a long write 821 // 822 if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) { 823 ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive); 824 if (!ReceiveFifoFull) { 825 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) { 826 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 827 EFI_ERROR_CODE, 828 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 829 SerialDevice->DevicePath 830 ); 831 if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) { 832 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 833 continue; 834 } 835 } 836 837 Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 838 839 IsaSerialFifoAdd (&SerialDevice->Receive, Data); 840 841 // 842 // For full handshake flow control, if receive buffer full 843 // tell the peer to stop sending data. 844 // 845 if (SerialDevice->HardwareFlowControl && 846 !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake) && 847 IsaSerialFifoFull (&SerialDevice->Receive) 848 ) { 849 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 850 Mcr.Bits.Rts = 0; 851 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 852 } 853 854 855 continue; 856 } else { 857 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 858 EFI_PROGRESS_CODE, 859 EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT, 860 SerialDevice->DevicePath 861 ); 862 } 863 } 864 // 865 // Do the write 866 // 867 if (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 868 // 869 // Make sure the transmit data will not be missed 870 // 871 if (SerialDevice->HardwareFlowControl) { 872 // 873 // For half handshake flow control assert RTS before sending. 874 // 875 if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) { 876 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 877 Mcr.Bits.Rts= 0; 878 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 879 } 880 // 881 // Wait for CTS 882 // 883 TimeOut = 0; 884 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 885 while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) || FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) { 886 gBS->Stall (TIMEOUT_STALL_INTERVAL); 887 TimeOut++; 888 if (TimeOut > 5) { 889 break; 890 } 891 892 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 893 } 894 895 if ((Msr.Bits.Dcd == 0) && ((Msr.Bits.Cts == 1) || FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) { 896 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); 897 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data); 898 } 899 900 // 901 // For half handshake flow control, tell DCE we are done. 902 // 903 if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) { 904 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 905 Mcr.Bits.Rts = 1; 906 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 907 } 908 } else { 909 IsaSerialFifoRemove (&SerialDevice->Transmit, &Data); 910 WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data); 911 } 912 } 913 } while (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)); 914 } 915 916 return EFI_SUCCESS; 917} 918 919// 920// Interface Functions 921// 922/** 923 Reset serial device. 924 925 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 926 927 @retval EFI_SUCCESS Reset successfully 928 @retval EFI_DEVICE_ERROR Failed to reset 929 930**/ 931EFI_STATUS 932EFIAPI 933IsaSerialReset ( 934 IN EFI_SERIAL_IO_PROTOCOL *This 935 ) 936{ 937 EFI_STATUS Status; 938 SERIAL_DEV *SerialDevice; 939 SERIAL_PORT_LCR Lcr; 940 SERIAL_PORT_IER Ier; 941 SERIAL_PORT_MCR Mcr; 942 SERIAL_PORT_FCR Fcr; 943 EFI_TPL Tpl; 944 945 SerialDevice = SERIAL_DEV_FROM_THIS (This); 946 947 // 948 // Report the status code reset the serial 949 // 950 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 951 EFI_PROGRESS_CODE, 952 EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT, 953 SerialDevice->DevicePath 954 ); 955 956 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 957 958 // 959 // Make sure DLAB is 0. 960 // 961 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 962 Lcr.Bits.DLab = 0; 963 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 964 965 // 966 // Turn off all interrupts 967 // 968 Ier.Data = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress); 969 Ier.Bits.Ravie = 0; 970 Ier.Bits.Theie = 0; 971 Ier.Bits.Rie = 0; 972 Ier.Bits.Mie = 0; 973 WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data); 974 975 // 976 // Disable the FIFO. 977 // 978 Fcr.Bits.TrFIFOE = 0; 979 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data); 980 981 // 982 // Turn off loopback and disable device interrupt. 983 // 984 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 985 Mcr.Bits.Out1 = 0; 986 Mcr.Bits.Out2 = 0; 987 Mcr.Bits.Lme = 0; 988 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 989 990 // 991 // Clear the scratch pad register 992 // 993 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0); 994 995 // 996 // Go set the current attributes 997 // 998 Status = This->SetAttributes ( 999 This, 1000 This->Mode->BaudRate, 1001 This->Mode->ReceiveFifoDepth, 1002 This->Mode->Timeout, 1003 (EFI_PARITY_TYPE) This->Mode->Parity, 1004 (UINT8) This->Mode->DataBits, 1005 (EFI_STOP_BITS_TYPE) This->Mode->StopBits 1006 ); 1007 1008 if (EFI_ERROR (Status)) { 1009 gBS->RestoreTPL (Tpl); 1010 return EFI_DEVICE_ERROR; 1011 } 1012 // 1013 // Go set the current control bits 1014 // 1015 Status = This->SetControl ( 1016 This, 1017 This->Mode->ControlMask 1018 ); 1019 1020 if (EFI_ERROR (Status)) { 1021 gBS->RestoreTPL (Tpl); 1022 return EFI_DEVICE_ERROR; 1023 } 1024 // 1025 // for 16550A enable FIFO, 16550 disable FIFO 1026 // 1027 Fcr.Bits.TrFIFOE = 1; 1028 Fcr.Bits.ResetRF = 1; 1029 Fcr.Bits.ResetTF = 1; 1030 WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data); 1031 1032 // 1033 // Reset the software FIFO 1034 // 1035 SerialDevice->Receive.First = 0; 1036 SerialDevice->Receive.Last = 0; 1037 SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE; 1038 SerialDevice->Transmit.First = 0; 1039 SerialDevice->Transmit.Last = 0; 1040 SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE; 1041 1042 gBS->RestoreTPL (Tpl); 1043 1044 // 1045 // Device reset is complete 1046 // 1047 return EFI_SUCCESS; 1048} 1049 1050/** 1051 Set new attributes to a serial device. 1052 1053 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1054 @param BaudRate The baudrate of the serial device 1055 @param ReceiveFifoDepth The depth of receive FIFO buffer 1056 @param Timeout The request timeout for a single char 1057 @param Parity The type of parity used in serial device 1058 @param DataBits Number of databits used in serial device 1059 @param StopBits Number of stopbits used in serial device 1060 1061 @retval EFI_SUCCESS The new attributes were set 1062 @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value 1063 @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6 1064 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return) 1065 1066**/ 1067EFI_STATUS 1068EFIAPI 1069IsaSerialSetAttributes ( 1070 IN EFI_SERIAL_IO_PROTOCOL *This, 1071 IN UINT64 BaudRate, 1072 IN UINT32 ReceiveFifoDepth, 1073 IN UINT32 Timeout, 1074 IN EFI_PARITY_TYPE Parity, 1075 IN UINT8 DataBits, 1076 IN EFI_STOP_BITS_TYPE StopBits 1077 ) 1078{ 1079 EFI_STATUS Status; 1080 SERIAL_DEV *SerialDevice; 1081 UINT32 Divisor; 1082 UINT32 Remained; 1083 SERIAL_PORT_LCR Lcr; 1084 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 1085 EFI_TPL Tpl; 1086 1087 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1088 1089 // 1090 // Check for default settings and fill in actual values. 1091 // 1092 if (BaudRate == 0) { 1093 BaudRate = FixedPcdGet64 (PcdUartDefaultBaudRate); 1094 } 1095 1096 if (ReceiveFifoDepth == 0) { 1097 ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH; 1098 } 1099 1100 if (Timeout == 0) { 1101 Timeout = SERIAL_PORT_DEFAULT_TIMEOUT; 1102 } 1103 1104 if (Parity == DefaultParity) { 1105 Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity); 1106 } 1107 1108 if (DataBits == 0) { 1109 DataBits = FixedPcdGet8 (PcdUartDefaultDataBits); 1110 } 1111 1112 if (StopBits == DefaultStopBits) { 1113 StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits); 1114 } 1115 // 1116 // 5 and 6 data bits can not be verified on a 16550A UART 1117 // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings. 1118 // 1119 if ((DataBits == 5) || (DataBits == 6)) { 1120 return EFI_INVALID_PARAMETER; 1121 } 1122 // 1123 // Make sure all parameters are valid 1124 // 1125 if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) { 1126 return EFI_INVALID_PARAMETER; 1127 } 1128 // 1129 // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200, 1130 // 38400,57600,115200 1131 // 1132 if (BaudRate < 75) { 1133 BaudRate = 50; 1134 } else if (BaudRate < 110) { 1135 BaudRate = 75; 1136 } else if (BaudRate < 134) { 1137 BaudRate = 110; 1138 } else if (BaudRate < 150) { 1139 BaudRate = 134; 1140 } else if (BaudRate < 300) { 1141 BaudRate = 150; 1142 } else if (BaudRate < 600) { 1143 BaudRate = 300; 1144 } else if (BaudRate < 1200) { 1145 BaudRate = 600; 1146 } else if (BaudRate < 1800) { 1147 BaudRate = 1200; 1148 } else if (BaudRate < 2000) { 1149 BaudRate = 1800; 1150 } else if (BaudRate < 2400) { 1151 BaudRate = 2000; 1152 } else if (BaudRate < 3600) { 1153 BaudRate = 2400; 1154 } else if (BaudRate < 4800) { 1155 BaudRate = 3600; 1156 } else if (BaudRate < 7200) { 1157 BaudRate = 4800; 1158 } else if (BaudRate < 9600) { 1159 BaudRate = 7200; 1160 } else if (BaudRate < 19200) { 1161 BaudRate = 9600; 1162 } else if (BaudRate < 38400) { 1163 BaudRate = 19200; 1164 } else if (BaudRate < 57600) { 1165 BaudRate = 38400; 1166 } else if (BaudRate < 115200) { 1167 BaudRate = 57600; 1168 } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) { 1169 BaudRate = 115200; 1170 } 1171 1172 if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) { 1173 return EFI_INVALID_PARAMETER; 1174 } 1175 1176 if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) { 1177 return EFI_INVALID_PARAMETER; 1178 } 1179 1180 if ((Parity < NoParity) || (Parity > SpaceParity)) { 1181 return EFI_INVALID_PARAMETER; 1182 } 1183 1184 if ((DataBits < 5) || (DataBits > 8)) { 1185 return EFI_INVALID_PARAMETER; 1186 } 1187 1188 if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) { 1189 return EFI_INVALID_PARAMETER; 1190 } 1191 1192 // 1193 // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits 1194 // 1195 if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) { 1196 return EFI_INVALID_PARAMETER; 1197 } 1198 1199 // 1200 // Compute divisor use to program the baud rate using a round determination 1201 // 1202 Divisor = (UINT32) DivU64x32Remainder ( 1203 SERIAL_PORT_INPUT_CLOCK, 1204 ((UINT32) BaudRate * 16), 1205 &Remained 1206 ); 1207 if (Remained != 0) { 1208 Divisor += 1; 1209 } 1210 1211 if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) { 1212 return EFI_INVALID_PARAMETER; 1213 } 1214 1215 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1216 1217 // 1218 // Compute the actual baud rate that the serial port will be programmed for. 1219 // 1220 BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16; 1221 1222 // 1223 // Put serial port on Divisor Latch Mode 1224 // 1225 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1226 Lcr.Bits.DLab = 1; 1227 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 1228 1229 // 1230 // Write the divisor to the serial port 1231 // 1232 WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff)); 1233 WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff)); 1234 1235 // 1236 // Put serial port back in normal mode and set remaining attributes. 1237 // 1238 Lcr.Bits.DLab = 0; 1239 1240 switch (Parity) { 1241 case NoParity: 1242 Lcr.Bits.ParEn = 0; 1243 Lcr.Bits.EvenPar = 0; 1244 Lcr.Bits.SticPar = 0; 1245 break; 1246 1247 case EvenParity: 1248 Lcr.Bits.ParEn = 1; 1249 Lcr.Bits.EvenPar = 1; 1250 Lcr.Bits.SticPar = 0; 1251 break; 1252 1253 case OddParity: 1254 Lcr.Bits.ParEn = 1; 1255 Lcr.Bits.EvenPar = 0; 1256 Lcr.Bits.SticPar = 0; 1257 break; 1258 1259 case SpaceParity: 1260 Lcr.Bits.ParEn = 1; 1261 Lcr.Bits.EvenPar = 1; 1262 Lcr.Bits.SticPar = 1; 1263 break; 1264 1265 case MarkParity: 1266 Lcr.Bits.ParEn = 1; 1267 Lcr.Bits.EvenPar = 0; 1268 Lcr.Bits.SticPar = 1; 1269 break; 1270 1271 default: 1272 break; 1273 } 1274 1275 switch (StopBits) { 1276 case OneStopBit: 1277 Lcr.Bits.StopB = 0; 1278 break; 1279 1280 case OneFiveStopBits: 1281 case TwoStopBits: 1282 Lcr.Bits.StopB = 1; 1283 break; 1284 1285 default: 1286 break; 1287 } 1288 // 1289 // DataBits 1290 // 1291 Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03); 1292 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 1293 1294 // 1295 // Set the Serial I/O mode 1296 // 1297 This->Mode->BaudRate = BaudRate; 1298 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; 1299 This->Mode->Timeout = Timeout; 1300 This->Mode->Parity = Parity; 1301 This->Mode->DataBits = DataBits; 1302 This->Mode->StopBits = StopBits; 1303 1304 // 1305 // See if Device Path Node has actually changed 1306 // 1307 if (SerialDevice->UartDevicePath.BaudRate == BaudRate && 1308 SerialDevice->UartDevicePath.DataBits == DataBits && 1309 SerialDevice->UartDevicePath.Parity == Parity && 1310 SerialDevice->UartDevicePath.StopBits == StopBits 1311 ) { 1312 gBS->RestoreTPL (Tpl); 1313 return EFI_SUCCESS; 1314 } 1315 // 1316 // Update the device path 1317 // 1318 SerialDevice->UartDevicePath.BaudRate = BaudRate; 1319 SerialDevice->UartDevicePath.DataBits = DataBits; 1320 SerialDevice->UartDevicePath.Parity = (UINT8) Parity; 1321 SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits; 1322 1323 NewDevicePath = AppendDevicePathNode ( 1324 SerialDevice->ParentDevicePath, 1325 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath 1326 ); 1327 if (NewDevicePath == NULL) { 1328 gBS->RestoreTPL (Tpl); 1329 return EFI_DEVICE_ERROR; 1330 } 1331 1332 if (SerialDevice->Handle != NULL) { 1333 Status = gBS->ReinstallProtocolInterface ( 1334 SerialDevice->Handle, 1335 &gEfiDevicePathProtocolGuid, 1336 SerialDevice->DevicePath, 1337 NewDevicePath 1338 ); 1339 if (EFI_ERROR (Status)) { 1340 gBS->RestoreTPL (Tpl); 1341 return Status; 1342 } 1343 } 1344 1345 if (SerialDevice->DevicePath != NULL) { 1346 gBS->FreePool (SerialDevice->DevicePath); 1347 } 1348 1349 SerialDevice->DevicePath = NewDevicePath; 1350 1351 gBS->RestoreTPL (Tpl); 1352 1353 return EFI_SUCCESS; 1354} 1355 1356/** 1357 Set Control Bits. 1358 1359 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1360 @param Control Control bits that can be settable 1361 1362 @retval EFI_SUCCESS New Control bits were set successfully 1363 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported 1364 1365**/ 1366EFI_STATUS 1367EFIAPI 1368IsaSerialSetControl ( 1369 IN EFI_SERIAL_IO_PROTOCOL *This, 1370 IN UINT32 Control 1371 ) 1372{ 1373 SERIAL_DEV *SerialDevice; 1374 SERIAL_PORT_MCR Mcr; 1375 EFI_TPL Tpl; 1376 1377 // 1378 // The control bits that can be set are : 1379 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO 1380 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO 1381 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW 1382 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW 1383 // 1384 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1385 1386 // 1387 // first determine the parameter is invalid 1388 // 1389 if ((Control & 0xffff8ffc) != 0) { 1390 return EFI_UNSUPPORTED; 1391 } 1392 1393 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1394 1395 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1396 Mcr.Bits.DtrC = 0; 1397 Mcr.Bits.Rts = 0; 1398 Mcr.Bits.Lme = 0; 1399 SerialDevice->SoftwareLoopbackEnable = FALSE; 1400 SerialDevice->HardwareFlowControl = FALSE; 1401 1402 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) { 1403 Mcr.Bits.DtrC = 1; 1404 } 1405 1406 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { 1407 Mcr.Bits.Rts = 1; 1408 } 1409 1410 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) { 1411 Mcr.Bits.Lme = 1; 1412 } 1413 1414 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { 1415 SerialDevice->HardwareFlowControl = TRUE; 1416 } 1417 1418 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 1419 1420 if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) { 1421 SerialDevice->SoftwareLoopbackEnable = TRUE; 1422 } 1423 1424 gBS->RestoreTPL (Tpl); 1425 1426 return EFI_SUCCESS; 1427} 1428 1429/** 1430 Get ControlBits. 1431 1432 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1433 @param Control Control signals of the serial device 1434 1435 @retval EFI_SUCCESS Get Control signals successfully 1436 1437**/ 1438EFI_STATUS 1439EFIAPI 1440IsaSerialGetControl ( 1441 IN EFI_SERIAL_IO_PROTOCOL *This, 1442 OUT UINT32 *Control 1443 ) 1444{ 1445 SERIAL_DEV *SerialDevice; 1446 SERIAL_PORT_MSR Msr; 1447 SERIAL_PORT_MCR Mcr; 1448 EFI_TPL Tpl; 1449 1450 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1451 1452 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1453 1454 *Control = 0; 1455 1456 // 1457 // Read the Modem Status Register 1458 // 1459 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1460 1461 if (Msr.Bits.Cts == 1) { 1462 *Control |= EFI_SERIAL_CLEAR_TO_SEND; 1463 } 1464 1465 if (Msr.Bits.Dsr == 1) { 1466 *Control |= EFI_SERIAL_DATA_SET_READY; 1467 } 1468 1469 if (Msr.Bits.Ri == 1) { 1470 *Control |= EFI_SERIAL_RING_INDICATE; 1471 } 1472 1473 if (Msr.Bits.Dcd == 1) { 1474 *Control |= EFI_SERIAL_CARRIER_DETECT; 1475 } 1476 // 1477 // Read the Modem Control Register 1478 // 1479 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1480 1481 if (Mcr.Bits.DtrC == 1) { 1482 *Control |= EFI_SERIAL_DATA_TERMINAL_READY; 1483 } 1484 1485 if (Mcr.Bits.Rts == 1) { 1486 *Control |= EFI_SERIAL_REQUEST_TO_SEND; 1487 } 1488 1489 if (Mcr.Bits.Lme == 1) { 1490 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; 1491 } 1492 1493 if (SerialDevice->HardwareFlowControl) { 1494 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; 1495 } 1496 // 1497 // See if the Transmit FIFO is empty 1498 // 1499 IsaSerialReceiveTransmit (SerialDevice); 1500 1501 if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 1502 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; 1503 } 1504 // 1505 // See if the Receive FIFO is empty. 1506 // 1507 IsaSerialReceiveTransmit (SerialDevice); 1508 1509 if (IsaSerialFifoEmpty (&SerialDevice->Receive)) { 1510 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; 1511 } 1512 1513 if (SerialDevice->SoftwareLoopbackEnable) { 1514 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; 1515 } 1516 1517 gBS->RestoreTPL (Tpl); 1518 1519 return EFI_SUCCESS; 1520} 1521 1522/** 1523 Write the specified number of bytes to serial device. 1524 1525 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1526 @param BufferSize On input the size of Buffer, on output the amount of 1527 data actually written 1528 @param Buffer The buffer of data to write 1529 1530 @retval EFI_SUCCESS The data were written successfully 1531 @retval EFI_DEVICE_ERROR The device reported an error 1532 @retval EFI_TIMEOUT The write operation was stopped due to timeout 1533 1534**/ 1535EFI_STATUS 1536EFIAPI 1537IsaSerialWrite ( 1538 IN EFI_SERIAL_IO_PROTOCOL *This, 1539 IN OUT UINTN *BufferSize, 1540 IN VOID *Buffer 1541 ) 1542{ 1543 SERIAL_DEV *SerialDevice; 1544 UINT8 *CharBuffer; 1545 UINT32 Index; 1546 UINTN Elapsed; 1547 UINTN ActualWrite; 1548 EFI_TPL Tpl; 1549 1550 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1551 Elapsed = 0; 1552 ActualWrite = 0; 1553 1554 if (*BufferSize == 0) { 1555 return EFI_SUCCESS; 1556 } 1557 1558 if (Buffer == NULL) { 1559 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1560 EFI_ERROR_CODE, 1561 EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 1562 SerialDevice->DevicePath 1563 ); 1564 1565 return EFI_DEVICE_ERROR; 1566 } 1567 1568 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1569 1570 CharBuffer = (UINT8 *) Buffer; 1571 1572 for (Index = 0; Index < *BufferSize; Index++) { 1573 IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]); 1574 1575 while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 1576 // 1577 // Unsuccessful write so check if timeout has expired, if not, 1578 // stall for a bit, increment time elapsed, and try again 1579 // 1580 if (Elapsed >= This->Mode->Timeout) { 1581 *BufferSize = ActualWrite; 1582 gBS->RestoreTPL (Tpl); 1583 return EFI_TIMEOUT; 1584 } 1585 1586 gBS->Stall (TIMEOUT_STALL_INTERVAL); 1587 1588 Elapsed += TIMEOUT_STALL_INTERVAL; 1589 } 1590 1591 ActualWrite++; 1592 // 1593 // Successful write so reset timeout 1594 // 1595 Elapsed = 0; 1596 } 1597 1598 gBS->RestoreTPL (Tpl); 1599 1600 return EFI_SUCCESS; 1601} 1602 1603/** 1604 Read the specified number of bytes from serial device. 1605 1606 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1607 @param BufferSize On input the size of Buffer, on output the amount of 1608 data returned in buffer 1609 @param Buffer The buffer to return the data into 1610 1611 @retval EFI_SUCCESS The data were read successfully 1612 @retval EFI_DEVICE_ERROR The device reported an error 1613 @retval EFI_TIMEOUT The read operation was stopped due to timeout 1614 1615**/ 1616EFI_STATUS 1617EFIAPI 1618IsaSerialRead ( 1619 IN EFI_SERIAL_IO_PROTOCOL *This, 1620 IN OUT UINTN *BufferSize, 1621 OUT VOID *Buffer 1622 ) 1623{ 1624 SERIAL_DEV *SerialDevice; 1625 UINT32 Index; 1626 UINT8 *CharBuffer; 1627 UINTN Elapsed; 1628 EFI_STATUS Status; 1629 EFI_TPL Tpl; 1630 1631 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1632 Elapsed = 0; 1633 1634 if (*BufferSize == 0) { 1635 return EFI_SUCCESS; 1636 } 1637 1638 if (Buffer == NULL) { 1639 return EFI_DEVICE_ERROR; 1640 } 1641 1642 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1643 1644 Status = IsaSerialReceiveTransmit (SerialDevice); 1645 1646 if (EFI_ERROR (Status)) { 1647 *BufferSize = 0; 1648 1649 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1650 EFI_ERROR_CODE, 1651 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 1652 SerialDevice->DevicePath 1653 ); 1654 1655 gBS->RestoreTPL (Tpl); 1656 1657 return EFI_DEVICE_ERROR; 1658 } 1659 1660 CharBuffer = (UINT8 *) Buffer; 1661 for (Index = 0; Index < *BufferSize; Index++) { 1662 while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) { 1663 // 1664 // Unsuccessful read so check if timeout has expired, if not, 1665 // stall for a bit, increment time elapsed, and try again 1666 // Need this time out to get conspliter to work. 1667 // 1668 if (Elapsed >= This->Mode->Timeout) { 1669 *BufferSize = Index; 1670 gBS->RestoreTPL (Tpl); 1671 return EFI_TIMEOUT; 1672 } 1673 1674 gBS->Stall (TIMEOUT_STALL_INTERVAL); 1675 Elapsed += TIMEOUT_STALL_INTERVAL; 1676 1677 Status = IsaSerialReceiveTransmit (SerialDevice); 1678 if (Status == EFI_DEVICE_ERROR) { 1679 *BufferSize = Index; 1680 gBS->RestoreTPL (Tpl); 1681 return EFI_DEVICE_ERROR; 1682 } 1683 } 1684 // 1685 // Successful read so reset timeout 1686 // 1687 Elapsed = 0; 1688 } 1689 1690 IsaSerialReceiveTransmit (SerialDevice); 1691 1692 gBS->RestoreTPL (Tpl); 1693 1694 return EFI_SUCCESS; 1695} 1696 1697/** 1698 Use scratchpad register to test if this serial port is present. 1699 1700 @param SerialDevice Pointer to serial device structure 1701 1702 @return if this serial port is present 1703**/ 1704BOOLEAN 1705IsaSerialPortPresent ( 1706 IN SERIAL_DEV *SerialDevice 1707 ) 1708 1709{ 1710 UINT8 Temp; 1711 BOOLEAN Status; 1712 1713 Status = TRUE; 1714 1715 // 1716 // Save SCR reg 1717 // 1718 Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1719 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA); 1720 1721 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) { 1722 Status = FALSE; 1723 } 1724 1725 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55); 1726 1727 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) { 1728 Status = FALSE; 1729 } 1730 // 1731 // Restore SCR 1732 // 1733 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp); 1734 return Status; 1735} 1736 1737/** 1738 Use IsaIo protocol to read serial port. 1739 1740 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance 1741 @param BaseAddress Serial port register group base address 1742 @param Offset Offset in register group 1743 1744 @return Data read from serial port 1745 1746**/ 1747UINT8 1748IsaSerialReadPort ( 1749 IN EFI_ISA_IO_PROTOCOL *IsaIo, 1750 IN UINT16 BaseAddress, 1751 IN UINT32 Offset 1752 ) 1753{ 1754 UINT8 Data; 1755 1756 // 1757 // Use IsaIo to access IO 1758 // 1759 IsaIo->Io.Read ( 1760 IsaIo, 1761 EfiIsaIoWidthUint8, 1762 BaseAddress + Offset, 1763 1, 1764 &Data 1765 ); 1766 return Data; 1767} 1768 1769/** 1770 Use IsaIo protocol to write serial port. 1771 1772 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance 1773 @param BaseAddress Serial port register group base address 1774 @param Offset Offset in register group 1775 @param Data data which is to be written to some serial port register 1776 1777**/ 1778VOID 1779IsaSerialWritePort ( 1780 IN EFI_ISA_IO_PROTOCOL *IsaIo, 1781 IN UINT16 BaseAddress, 1782 IN UINT32 Offset, 1783 IN UINT8 Data 1784 ) 1785{ 1786 // 1787 // Use IsaIo to access IO 1788 // 1789 IsaIo->Io.Write ( 1790 IsaIo, 1791 EfiIsaIoWidthUint8, 1792 BaseAddress + Offset, 1793 1, 1794 &Data 1795 ); 1796} 1797 1798