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