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