]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c
Replace Fixed PCD with Feature PCD for useHalfHandshake to reduce code size.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaSerialDxe / Serial.c
1 /** @file
2 Serial driver for standard UARTS on an ISA bus.
3
4 Copyright (c) 2006 - 2009, Intel Corporation<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Serial.h"
16
17 //
18 // ISA Serial Driver Global Variables
19 //
20 EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
21 SerialControllerDriverSupported,
22 SerialControllerDriverStart,
23 SerialControllerDriverStop,
24 0xa,
25 NULL,
26 NULL
27 };
28
29
30 SERIAL_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 **/
99 EFI_STATUS
100 EFIAPI
101 InitializeIsaSerial (
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 **/
135 EFI_STATUS
136 EFIAPI
137 SerialControllerDriverSupported (
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
247 Error:
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 **/
271 EFI_STATUS
272 EFIAPI
273 SerialControllerDriverStart (
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
490 Error:
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 **/
529 EFI_STATUS
530 EFIAPI
531 SerialControllerDriverStop (
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 **/
656 BOOLEAN
657 IsaSerialFifoFull (
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 **/
677 BOOLEAN
678 IsaSerialFifoEmpty (
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 **/
700 EFI_STATUS
701 IsaSerialFifoAdd (
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 **/
736 EFI_STATUS
737 IsaSerialFifoRemove (
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 **/
772 EFI_STATUS
773 IsaSerialReceiveTransmit (
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 **/
931 EFI_STATUS
932 EFIAPI
933 IsaSerialReset (
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 **/
1067 EFI_STATUS
1068 EFIAPI
1069 IsaSerialSetAttributes (
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 **/
1371 EFI_STATUS
1372 EFIAPI
1373 IsaSerialSetControl (
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 **/
1443 EFI_STATUS
1444 EFIAPI
1445 IsaSerialGetControl (
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 **/
1540 EFI_STATUS
1541 EFIAPI
1542 IsaSerialWrite (
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 **/
1621 EFI_STATUS
1622 EFIAPI
1623 IsaSerialRead (
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 **/
1709 BOOLEAN
1710 IsaSerialPortPresent (
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 **/
1752 UINT8
1753 IsaSerialReadPort (
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 **/
1783 VOID
1784 IsaSerialWritePort (
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