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