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