Serial.c revision 77b91d896f2183906a8e54dd2a82af3a213883be
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 ^ 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 ^ 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 // for DataBits = 5, StopBits can not set TwoStopBits 1193 // 1194 // if ((DataBits == 5) && (StopBits == TwoStopBits)) { 1195 // return EFI_INVALID_PARAMETER; 1196 // } 1197 // 1198 // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits 1199 // 1200 if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) { 1201 return EFI_INVALID_PARAMETER; 1202 } 1203 1204 // 1205 // Compute divisor use to program the baud rate using a round determination 1206 // 1207 Divisor = (UINT32) DivU64x32Remainder ( 1208 SERIAL_PORT_INPUT_CLOCK, 1209 ((UINT32) BaudRate * 16), 1210 &Remained 1211 ); 1212 if (Remained != 0) { 1213 Divisor += 1; 1214 } 1215 1216 if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) { 1217 return EFI_INVALID_PARAMETER; 1218 } 1219 1220 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1221 1222 // 1223 // Compute the actual baud rate that the serial port will be programmed for. 1224 // 1225 BaudRate = SERIAL_PORT_INPUT_CLOCK / Divisor / 16; 1226 1227 // 1228 // Put serial port on Divisor Latch Mode 1229 // 1230 Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1231 Lcr.Bits.DLab = 1; 1232 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 1233 1234 // 1235 // Write the divisor to the serial port 1236 // 1237 WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff)); 1238 WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff)); 1239 1240 // 1241 // Put serial port back in normal mode and set remaining attributes. 1242 // 1243 Lcr.Bits.DLab = 0; 1244 1245 switch (Parity) { 1246 case NoParity: 1247 Lcr.Bits.ParEn = 0; 1248 Lcr.Bits.EvenPar = 0; 1249 Lcr.Bits.SticPar = 0; 1250 break; 1251 1252 case EvenParity: 1253 Lcr.Bits.ParEn = 1; 1254 Lcr.Bits.EvenPar = 1; 1255 Lcr.Bits.SticPar = 0; 1256 break; 1257 1258 case OddParity: 1259 Lcr.Bits.ParEn = 1; 1260 Lcr.Bits.EvenPar = 0; 1261 Lcr.Bits.SticPar = 0; 1262 break; 1263 1264 case SpaceParity: 1265 Lcr.Bits.ParEn = 1; 1266 Lcr.Bits.EvenPar = 1; 1267 Lcr.Bits.SticPar = 1; 1268 break; 1269 1270 case MarkParity: 1271 Lcr.Bits.ParEn = 1; 1272 Lcr.Bits.EvenPar = 0; 1273 Lcr.Bits.SticPar = 1; 1274 break; 1275 1276 default: 1277 break; 1278 } 1279 1280 switch (StopBits) { 1281 case OneStopBit: 1282 Lcr.Bits.StopB = 0; 1283 break; 1284 1285 case OneFiveStopBits: 1286 case TwoStopBits: 1287 Lcr.Bits.StopB = 1; 1288 break; 1289 1290 default: 1291 break; 1292 } 1293 // 1294 // DataBits 1295 // 1296 Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03); 1297 WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data); 1298 1299 // 1300 // Set the Serial I/O mode 1301 // 1302 This->Mode->BaudRate = BaudRate; 1303 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; 1304 This->Mode->Timeout = Timeout; 1305 This->Mode->Parity = Parity; 1306 This->Mode->DataBits = DataBits; 1307 This->Mode->StopBits = StopBits; 1308 1309 // 1310 // See if Device Path Node has actually changed 1311 // 1312 if (SerialDevice->UartDevicePath.BaudRate == BaudRate && 1313 SerialDevice->UartDevicePath.DataBits == DataBits && 1314 SerialDevice->UartDevicePath.Parity == Parity && 1315 SerialDevice->UartDevicePath.StopBits == StopBits 1316 ) { 1317 gBS->RestoreTPL (Tpl); 1318 return EFI_SUCCESS; 1319 } 1320 // 1321 // Update the device path 1322 // 1323 SerialDevice->UartDevicePath.BaudRate = BaudRate; 1324 SerialDevice->UartDevicePath.DataBits = DataBits; 1325 SerialDevice->UartDevicePath.Parity = (UINT8) Parity; 1326 SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits; 1327 1328 NewDevicePath = AppendDevicePathNode ( 1329 SerialDevice->ParentDevicePath, 1330 (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath 1331 ); 1332 if (NewDevicePath == NULL) { 1333 gBS->RestoreTPL (Tpl); 1334 return EFI_DEVICE_ERROR; 1335 } 1336 1337 if (SerialDevice->Handle != NULL) { 1338 Status = gBS->ReinstallProtocolInterface ( 1339 SerialDevice->Handle, 1340 &gEfiDevicePathProtocolGuid, 1341 SerialDevice->DevicePath, 1342 NewDevicePath 1343 ); 1344 if (EFI_ERROR (Status)) { 1345 gBS->RestoreTPL (Tpl); 1346 return Status; 1347 } 1348 } 1349 1350 if (SerialDevice->DevicePath != NULL) { 1351 gBS->FreePool (SerialDevice->DevicePath); 1352 } 1353 1354 SerialDevice->DevicePath = NewDevicePath; 1355 1356 gBS->RestoreTPL (Tpl); 1357 1358 return EFI_SUCCESS; 1359} 1360 1361/** 1362 Set Control Bits. 1363 1364 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1365 @param Control Control bits that can be settable 1366 1367 @retval EFI_SUCCESS New Control bits were set successfully 1368 @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported 1369 1370**/ 1371EFI_STATUS 1372EFIAPI 1373IsaSerialSetControl ( 1374 IN EFI_SERIAL_IO_PROTOCOL *This, 1375 IN UINT32 Control 1376 ) 1377{ 1378 SERIAL_DEV *SerialDevice; 1379 SERIAL_PORT_MCR Mcr; 1380 EFI_TPL Tpl; 1381 1382 // 1383 // The control bits that can be set are : 1384 // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO 1385 // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO 1386 // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW 1387 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW 1388 // 1389 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1390 1391 // 1392 // first determine the parameter is invalid 1393 // 1394 if ((Control & 0xffff8ffc) != 0) { 1395 return EFI_UNSUPPORTED; 1396 } 1397 1398 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1399 1400 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1401 Mcr.Bits.DtrC = 0; 1402 Mcr.Bits.Rts = 0; 1403 Mcr.Bits.Lme = 0; 1404 SerialDevice->SoftwareLoopbackEnable = FALSE; 1405 SerialDevice->HardwareFlowControl = FALSE; 1406 1407 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) { 1408 Mcr.Bits.DtrC = 1; 1409 } 1410 1411 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { 1412 Mcr.Bits.Rts = 1; 1413 } 1414 1415 if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) { 1416 Mcr.Bits.Lme = 1; 1417 } 1418 1419 if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { 1420 SerialDevice->HardwareFlowControl = TRUE; 1421 } 1422 1423 WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data); 1424 1425 if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) { 1426 SerialDevice->SoftwareLoopbackEnable = TRUE; 1427 } 1428 1429 gBS->RestoreTPL (Tpl); 1430 1431 return EFI_SUCCESS; 1432} 1433 1434/** 1435 Get ControlBits. 1436 1437 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1438 @param Control Control signals of the serial device 1439 1440 @retval EFI_SUCCESS Get Control signals successfully 1441 1442**/ 1443EFI_STATUS 1444EFIAPI 1445IsaSerialGetControl ( 1446 IN EFI_SERIAL_IO_PROTOCOL *This, 1447 OUT UINT32 *Control 1448 ) 1449{ 1450 SERIAL_DEV *SerialDevice; 1451 SERIAL_PORT_MSR Msr; 1452 SERIAL_PORT_MCR Mcr; 1453 EFI_TPL Tpl; 1454 1455 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1456 1457 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1458 1459 *Control = 0; 1460 1461 // 1462 // Read the Modem Status Register 1463 // 1464 Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1465 1466 if (Msr.Bits.Cts == 1) { 1467 *Control |= EFI_SERIAL_CLEAR_TO_SEND; 1468 } 1469 1470 if (Msr.Bits.Dsr == 1) { 1471 *Control |= EFI_SERIAL_DATA_SET_READY; 1472 } 1473 1474 if (Msr.Bits.Ri == 1) { 1475 *Control |= EFI_SERIAL_RING_INDICATE; 1476 } 1477 1478 if (Msr.Bits.Dcd == 1) { 1479 *Control |= EFI_SERIAL_CARRIER_DETECT; 1480 } 1481 // 1482 // Read the Modem Control Register 1483 // 1484 Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1485 1486 if (Mcr.Bits.DtrC == 1) { 1487 *Control |= EFI_SERIAL_DATA_TERMINAL_READY; 1488 } 1489 1490 if (Mcr.Bits.Rts == 1) { 1491 *Control |= EFI_SERIAL_REQUEST_TO_SEND; 1492 } 1493 1494 if (Mcr.Bits.Lme == 1) { 1495 *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; 1496 } 1497 1498 if (SerialDevice->HardwareFlowControl) { 1499 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; 1500 } 1501 // 1502 // See if the Transmit FIFO is empty 1503 // 1504 IsaSerialReceiveTransmit (SerialDevice); 1505 1506 if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 1507 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; 1508 } 1509 // 1510 // See if the Receive FIFO is empty. 1511 // 1512 IsaSerialReceiveTransmit (SerialDevice); 1513 1514 if (IsaSerialFifoEmpty (&SerialDevice->Receive)) { 1515 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; 1516 } 1517 1518 if (SerialDevice->SoftwareLoopbackEnable) { 1519 *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; 1520 } 1521 1522 gBS->RestoreTPL (Tpl); 1523 1524 return EFI_SUCCESS; 1525} 1526 1527/** 1528 Write the specified number of bytes to serial device. 1529 1530 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1531 @param BufferSize On input the size of Buffer, on output the amount of 1532 data actually written 1533 @param Buffer The buffer of data to write 1534 1535 @retval EFI_SUCCESS The data were written successfully 1536 @retval EFI_DEVICE_ERROR The device reported an error 1537 @retval EFI_TIMEOUT The write operation was stopped due to timeout 1538 1539**/ 1540EFI_STATUS 1541EFIAPI 1542IsaSerialWrite ( 1543 IN EFI_SERIAL_IO_PROTOCOL *This, 1544 IN OUT UINTN *BufferSize, 1545 IN VOID *Buffer 1546 ) 1547{ 1548 SERIAL_DEV *SerialDevice; 1549 UINT8 *CharBuffer; 1550 UINT32 Index; 1551 UINTN Elapsed; 1552 UINTN ActualWrite; 1553 EFI_TPL Tpl; 1554 1555 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1556 Elapsed = 0; 1557 ActualWrite = 0; 1558 1559 if (*BufferSize == 0) { 1560 return EFI_SUCCESS; 1561 } 1562 1563 if (Buffer == NULL) { 1564 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1565 EFI_ERROR_CODE, 1566 EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 1567 SerialDevice->DevicePath 1568 ); 1569 1570 return EFI_DEVICE_ERROR; 1571 } 1572 1573 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1574 1575 CharBuffer = (UINT8 *) Buffer; 1576 1577 for (Index = 0; Index < *BufferSize; Index++) { 1578 IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]); 1579 1580 while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) { 1581 // 1582 // Unsuccessful write so check if timeout has expired, if not, 1583 // stall for a bit, increment time elapsed, and try again 1584 // 1585 if (Elapsed >= This->Mode->Timeout) { 1586 *BufferSize = ActualWrite; 1587 gBS->RestoreTPL (Tpl); 1588 return EFI_TIMEOUT; 1589 } 1590 1591 gBS->Stall (TIMEOUT_STALL_INTERVAL); 1592 1593 Elapsed += TIMEOUT_STALL_INTERVAL; 1594 } 1595 1596 ActualWrite++; 1597 // 1598 // Successful write so reset timeout 1599 // 1600 Elapsed = 0; 1601 } 1602 1603 gBS->RestoreTPL (Tpl); 1604 1605 return EFI_SUCCESS; 1606} 1607 1608/** 1609 Read the specified number of bytes from serial device. 1610 1611 @param This Pointer to EFI_SERIAL_IO_PROTOCOL 1612 @param BufferSize On input the size of Buffer, on output the amount of 1613 data returned in buffer 1614 @param Buffer The buffer to return the data into 1615 1616 @retval EFI_SUCCESS The data were read successfully 1617 @retval EFI_DEVICE_ERROR The device reported an error 1618 @retval EFI_TIMEOUT The read operation was stopped due to timeout 1619 1620**/ 1621EFI_STATUS 1622EFIAPI 1623IsaSerialRead ( 1624 IN EFI_SERIAL_IO_PROTOCOL *This, 1625 IN OUT UINTN *BufferSize, 1626 OUT VOID *Buffer 1627 ) 1628{ 1629 SERIAL_DEV *SerialDevice; 1630 UINT32 Index; 1631 UINT8 *CharBuffer; 1632 UINTN Elapsed; 1633 EFI_STATUS Status; 1634 EFI_TPL Tpl; 1635 1636 SerialDevice = SERIAL_DEV_FROM_THIS (This); 1637 Elapsed = 0; 1638 1639 if (*BufferSize == 0) { 1640 return EFI_SUCCESS; 1641 } 1642 1643 if (Buffer == NULL) { 1644 return EFI_DEVICE_ERROR; 1645 } 1646 1647 Tpl = gBS->RaiseTPL (TPL_NOTIFY); 1648 1649 Status = IsaSerialReceiveTransmit (SerialDevice); 1650 1651 if (EFI_ERROR (Status)) { 1652 *BufferSize = 0; 1653 1654 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1655 EFI_ERROR_CODE, 1656 EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, 1657 SerialDevice->DevicePath 1658 ); 1659 1660 gBS->RestoreTPL (Tpl); 1661 1662 return EFI_DEVICE_ERROR; 1663 } 1664 1665 CharBuffer = (UINT8 *) Buffer; 1666 for (Index = 0; Index < *BufferSize; Index++) { 1667 while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) { 1668 // 1669 // Unsuccessful read so check if timeout has expired, if not, 1670 // stall for a bit, increment time elapsed, and try again 1671 // Need this time out to get conspliter to work. 1672 // 1673 if (Elapsed >= This->Mode->Timeout) { 1674 *BufferSize = Index; 1675 gBS->RestoreTPL (Tpl); 1676 return EFI_TIMEOUT; 1677 } 1678 1679 gBS->Stall (TIMEOUT_STALL_INTERVAL); 1680 Elapsed += TIMEOUT_STALL_INTERVAL; 1681 1682 Status = IsaSerialReceiveTransmit (SerialDevice); 1683 if (Status == EFI_DEVICE_ERROR) { 1684 *BufferSize = Index; 1685 gBS->RestoreTPL (Tpl); 1686 return EFI_DEVICE_ERROR; 1687 } 1688 } 1689 // 1690 // Successful read so reset timeout 1691 // 1692 Elapsed = 0; 1693 } 1694 1695 IsaSerialReceiveTransmit (SerialDevice); 1696 1697 gBS->RestoreTPL (Tpl); 1698 1699 return EFI_SUCCESS; 1700} 1701 1702/** 1703 Use scratchpad register to test if this serial port is present. 1704 1705 @param SerialDevice Pointer to serial device structure 1706 1707 @return if this serial port is present 1708**/ 1709BOOLEAN 1710IsaSerialPortPresent ( 1711 IN SERIAL_DEV *SerialDevice 1712 ) 1713 1714{ 1715 UINT8 Temp; 1716 BOOLEAN Status; 1717 1718 Status = TRUE; 1719 1720 // 1721 // Save SCR reg 1722 // 1723 Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress); 1724 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA); 1725 1726 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) { 1727 Status = FALSE; 1728 } 1729 1730 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55); 1731 1732 if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) { 1733 Status = FALSE; 1734 } 1735 // 1736 // Restore SCR 1737 // 1738 WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp); 1739 return Status; 1740} 1741 1742/** 1743 Use IsaIo protocol to read serial port. 1744 1745 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance 1746 @param BaseAddress Serial port register group base address 1747 @param Offset Offset in register group 1748 1749 @return Data read from serial port 1750 1751**/ 1752UINT8 1753IsaSerialReadPort ( 1754 IN EFI_ISA_IO_PROTOCOL *IsaIo, 1755 IN UINT16 BaseAddress, 1756 IN UINT32 Offset 1757 ) 1758{ 1759 UINT8 Data; 1760 1761 // 1762 // Use IsaIo to access IO 1763 // 1764 IsaIo->Io.Read ( 1765 IsaIo, 1766 EfiIsaIoWidthUint8, 1767 BaseAddress + Offset, 1768 1, 1769 &Data 1770 ); 1771 return Data; 1772} 1773 1774/** 1775 Use IsaIo protocol to write serial port. 1776 1777 @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance 1778 @param BaseAddress Serial port register group base address 1779 @param Offset Offset in register group 1780 @param Data data which is to be written to some serial port register 1781 1782**/ 1783VOID 1784IsaSerialWritePort ( 1785 IN EFI_ISA_IO_PROTOCOL *IsaIo, 1786 IN UINT16 BaseAddress, 1787 IN UINT32 Offset, 1788 IN UINT8 Data 1789 ) 1790{ 1791 // 1792 // Use IsaIo to access IO 1793 // 1794 IsaIo->Io.Write ( 1795 IsaIo, 1796 EfiIsaIoWidthUint8, 1797 BaseAddress + Offset, 1798 1, 1799 &Data 1800 ); 1801} 1802 1803