]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/SerialDxe/SerialIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / SerialDxe / SerialIo.c
... / ...
CommitLineData
1/** @file\r
2 Serial driver that layers on top of a Serial Port Library instance.\r
3\r
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
5 Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
6 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
7\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12#include <Library/UefiBootServicesTableLib.h>\r
13#include <Library/SerialPortLib.h>\r
14#include <Library/DebugLib.h>\r
15#include <Library/PcdLib.h>\r
16\r
17#include <Protocol/SerialIo.h>\r
18#include <Protocol/DevicePath.h>\r
19#include <Guid/SerialPortLibVendor.h>\r
20\r
21typedef struct {\r
22 VENDOR_DEVICE_PATH Guid;\r
23 UART_DEVICE_PATH Uart;\r
24 EFI_DEVICE_PATH_PROTOCOL End;\r
25} SERIAL_DEVICE_PATH;\r
26\r
27/**\r
28 Reset the serial device.\r
29\r
30 @param This Protocol instance pointer.\r
31\r
32 @retval EFI_SUCCESS The device was reset.\r
33 @retval EFI_DEVICE_ERROR The serial device could not be reset.\r
34\r
35**/\r
36EFI_STATUS\r
37EFIAPI\r
38SerialReset (\r
39 IN EFI_SERIAL_IO_PROTOCOL *This\r
40 );\r
41\r
42/**\r
43 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
44 data bits, and stop bits on a serial device.\r
45\r
46 @param This Protocol instance pointer.\r
47 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the\r
48 device's default interface speed.\r
49 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
50 serial interface. A ReceiveFifoDepth value of 0 will use\r
51 the device's default FIFO depth.\r
52 @param Timeout The requested time out for a single character in microseconds.\r
53 This timeout applies to both the transmit and receive side of the\r
54 interface. A Timeout value of 0 will use the device's default time\r
55 out value.\r
56 @param Parity The type of parity to use on this serial device. A Parity value of\r
57 DefaultParity will use the device's default parity value.\r
58 @param DataBits The number of data bits to use on the serial device. A DataBits\r
59 value of 0 will use the device's default data bit setting.\r
60 @param StopBits The number of stop bits to use on this serial device. A StopBits\r
61 value of DefaultStopBits will use the device's default number of\r
62 stop bits.\r
63\r
64 @retval EFI_SUCCESS The device was reset.\r
65 @retval EFI_INVALID_PARAMETER One or more attributes has an unsupported value.\r
66 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
67\r
68**/\r
69EFI_STATUS\r
70EFIAPI\r
71SerialSetAttributes (\r
72 IN EFI_SERIAL_IO_PROTOCOL *This,\r
73 IN UINT64 BaudRate,\r
74 IN UINT32 ReceiveFifoDepth,\r
75 IN UINT32 Timeout,\r
76 IN EFI_PARITY_TYPE Parity,\r
77 IN UINT8 DataBits,\r
78 IN EFI_STOP_BITS_TYPE StopBits\r
79 );\r
80\r
81/**\r
82 Set the control bits on a serial device\r
83\r
84 @param This Protocol instance pointer.\r
85 @param Control Set the bits of Control that are settable.\r
86\r
87 @retval EFI_SUCCESS The new control bits were set on the serial device.\r
88 @retval EFI_UNSUPPORTED The serial device does not support this operation.\r
89 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
90\r
91**/\r
92EFI_STATUS\r
93EFIAPI\r
94SerialSetControl (\r
95 IN EFI_SERIAL_IO_PROTOCOL *This,\r
96 IN UINT32 Control\r
97 );\r
98\r
99/**\r
100 Retrieves the status of the control bits on a serial device\r
101\r
102 @param This Protocol instance pointer.\r
103 @param Control A pointer to return the current Control signals from the serial device.\r
104\r
105 @retval EFI_SUCCESS The control bits were read from the serial device.\r
106 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
107\r
108**/\r
109EFI_STATUS\r
110EFIAPI\r
111SerialGetControl (\r
112 IN EFI_SERIAL_IO_PROTOCOL *This,\r
113 OUT UINT32 *Control\r
114 );\r
115\r
116/**\r
117 Writes data to a serial device.\r
118\r
119 @param This Protocol instance pointer.\r
120 @param BufferSize On input, the size of the Buffer. On output, the amount of\r
121 data actually written.\r
122 @param Buffer The buffer of data to write\r
123\r
124 @retval EFI_SUCCESS The data was written.\r
125 @retval EFI_DEVICE_ERROR The device reported an error.\r
126 @retval EFI_TIMEOUT The data write was stopped due to a timeout.\r
127\r
128**/\r
129EFI_STATUS\r
130EFIAPI\r
131SerialWrite (\r
132 IN EFI_SERIAL_IO_PROTOCOL *This,\r
133 IN OUT UINTN *BufferSize,\r
134 IN VOID *Buffer\r
135 );\r
136\r
137/**\r
138 Reads data from a serial device.\r
139\r
140 @param This Protocol instance pointer.\r
141 @param BufferSize On input, the size of the Buffer. On output, the amount of\r
142 data returned in Buffer.\r
143 @param Buffer The buffer to return the data into.\r
144\r
145 @retval EFI_SUCCESS The data was read.\r
146 @retval EFI_DEVICE_ERROR The device reported an error.\r
147 @retval EFI_TIMEOUT The data write was stopped due to a timeout.\r
148\r
149**/\r
150EFI_STATUS\r
151EFIAPI\r
152SerialRead (\r
153 IN EFI_SERIAL_IO_PROTOCOL *This,\r
154 IN OUT UINTN *BufferSize,\r
155 OUT VOID *Buffer\r
156 );\r
157\r
158EFI_HANDLE mSerialHandle = NULL;\r
159\r
160SERIAL_DEVICE_PATH mSerialDevicePath = {\r
161 {\r
162 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} },\r
163 EDKII_SERIAL_PORT_LIB_VENDOR_GUID\r
164 },\r
165 {\r
166 { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} },\r
167 0, // Reserved\r
168 0, // BaudRate\r
169 0, // DataBits\r
170 0, // Parity\r
171 0 // StopBits\r
172 },\r
173 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }\r
174};\r
175\r
176//\r
177// Template used to initialize the Serial IO protocols.\r
178//\r
179EFI_SERIAL_IO_MODE mSerialIoMode = {\r
180 //\r
181 // value field set in SerialDxeInitialize()?\r
182 //--------- ------------------- -----------------------------\r
183 0, // ControlMask\r
184 1000 * 1000, // Timeout\r
185 0, // BaudRate yes\r
186 1, // ReceiveFifoDepth\r
187 0, // DataBits yes\r
188 0, // Parity yes\r
189 0 // StopBits yes\r
190};\r
191\r
192EFI_SERIAL_IO_PROTOCOL mSerialIoTemplate = {\r
193 SERIAL_IO_INTERFACE_REVISION,\r
194 SerialReset,\r
195 SerialSetAttributes,\r
196 SerialSetControl,\r
197 SerialGetControl,\r
198 SerialWrite,\r
199 SerialRead,\r
200 &mSerialIoMode\r
201};\r
202\r
203/**\r
204 Reset the serial device.\r
205\r
206 @param This Protocol instance pointer.\r
207\r
208 @retval EFI_SUCCESS The device was reset.\r
209 @retval EFI_DEVICE_ERROR The serial device could not be reset.\r
210\r
211**/\r
212EFI_STATUS\r
213EFIAPI\r
214SerialReset (\r
215 IN EFI_SERIAL_IO_PROTOCOL *This\r
216 )\r
217{\r
218 EFI_STATUS Status;\r
219\r
220 Status = SerialPortInitialize ();\r
221 if (EFI_ERROR (Status)) {\r
222 return Status;\r
223 }\r
224\r
225 //\r
226 // Go set the current attributes\r
227 //\r
228 Status = This->SetAttributes (\r
229 This,\r
230 This->Mode->BaudRate,\r
231 This->Mode->ReceiveFifoDepth,\r
232 This->Mode->Timeout,\r
233 (EFI_PARITY_TYPE) This->Mode->Parity,\r
234 (UINT8) This->Mode->DataBits,\r
235 (EFI_STOP_BITS_TYPE) This->Mode->StopBits\r
236 );\r
237\r
238 //\r
239 // The serial device may not support some of the attributes. To prevent\r
240 // later failure, always return EFI_SUCCESS when SetAttributes is returning\r
241 // EFI_INVALID_PARAMETER.\r
242 //\r
243 if (Status == EFI_INVALID_PARAMETER) {\r
244 return EFI_SUCCESS;\r
245 }\r
246\r
247 return Status;\r
248}\r
249\r
250/**\r
251 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,\r
252 data bits, and stop bits on a serial device.\r
253\r
254 @param This Protocol instance pointer.\r
255 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the\r
256 device's default interface speed.\r
257 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the\r
258 serial interface. A ReceiveFifoDepth value of 0 will use\r
259 the device's default FIFO depth.\r
260 @param Timeout The requested time out for a single character in microseconds.\r
261 This timeout applies to both the transmit and receive side of the\r
262 interface. A Timeout value of 0 will use the device's default time\r
263 out value.\r
264 @param Parity The type of parity to use on this serial device. A Parity value of\r
265 DefaultParity will use the device's default parity value.\r
266 @param DataBits The number of data bits to use on the serial device. A DataBits\r
267 value of 0 will use the device's default data bit setting.\r
268 @param StopBits The number of stop bits to use on this serial device. A StopBits\r
269 value of DefaultStopBits will use the device's default number of\r
270 stop bits.\r
271\r
272 @retval EFI_SUCCESS The device was reset.\r
273 @retval EFI_INVALID_PARAMETER One or more attributes has an unsupported value.\r
274 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
275\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279SerialSetAttributes (\r
280 IN EFI_SERIAL_IO_PROTOCOL *This,\r
281 IN UINT64 BaudRate,\r
282 IN UINT32 ReceiveFifoDepth,\r
283 IN UINT32 Timeout,\r
284 IN EFI_PARITY_TYPE Parity,\r
285 IN UINT8 DataBits,\r
286 IN EFI_STOP_BITS_TYPE StopBits\r
287 )\r
288{\r
289 EFI_STATUS Status;\r
290 EFI_TPL Tpl;\r
291 UINT64 OriginalBaudRate;\r
292 UINT32 OriginalReceiveFifoDepth;\r
293 UINT32 OriginalTimeout;\r
294 EFI_PARITY_TYPE OriginalParity;\r
295 UINT8 OriginalDataBits;\r
296 EFI_STOP_BITS_TYPE OriginalStopBits;\r
297\r
298 //\r
299 // Preserve the original input values in case\r
300 // SerialPortSetAttributes() updates the input/output\r
301 // parameters even on error.\r
302 //\r
303 OriginalBaudRate = BaudRate;\r
304 OriginalReceiveFifoDepth = ReceiveFifoDepth;\r
305 OriginalTimeout = Timeout;\r
306 OriginalParity = Parity;\r
307 OriginalDataBits = DataBits;\r
308 OriginalStopBits = StopBits;\r
309 Status = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits);\r
310 if (EFI_ERROR (Status)) {\r
311 //\r
312 // If it is just to set Timeout value and unsupported is returned,\r
313 // do not return error.\r
314 //\r
315 if ((Status == EFI_UNSUPPORTED) &&\r
316 (This->Mode->Timeout != OriginalTimeout) &&\r
317 (This->Mode->ReceiveFifoDepth == OriginalReceiveFifoDepth) &&\r
318 (This->Mode->BaudRate == OriginalBaudRate) &&\r
319 (This->Mode->DataBits == (UINT32) OriginalDataBits) &&\r
320 (This->Mode->Parity == (UINT32) OriginalParity) &&\r
321 (This->Mode->StopBits == (UINT32) OriginalStopBits)) {\r
322 //\r
323 // Restore to the original input values.\r
324 //\r
325 BaudRate = OriginalBaudRate;\r
326 ReceiveFifoDepth = OriginalReceiveFifoDepth;\r
327 Timeout = OriginalTimeout;\r
328 Parity = OriginalParity;\r
329 DataBits = OriginalDataBits;\r
330 StopBits = OriginalStopBits;\r
331 Status = EFI_SUCCESS;\r
332 } else if (Status == EFI_INVALID_PARAMETER || Status == EFI_UNSUPPORTED) {\r
333 return EFI_INVALID_PARAMETER;\r
334 } else {\r
335 return EFI_DEVICE_ERROR;\r
336 }\r
337 }\r
338\r
339 //\r
340 // Set the Serial I/O mode and update the device path\r
341 //\r
342\r
343 Tpl = gBS->RaiseTPL (TPL_NOTIFY);\r
344\r
345 //\r
346 // Set the Serial I/O mode\r
347 //\r
348 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;\r
349 This->Mode->Timeout = Timeout;\r
350 This->Mode->BaudRate = BaudRate;\r
351 This->Mode->DataBits = (UINT32) DataBits;\r
352 This->Mode->Parity = (UINT32) Parity;\r
353 This->Mode->StopBits = (UINT32) StopBits;\r
354\r
355 //\r
356 // Check if the device path has actually changed\r
357 //\r
358 if (mSerialDevicePath.Uart.BaudRate == BaudRate &&\r
359 mSerialDevicePath.Uart.DataBits == DataBits &&\r
360 mSerialDevicePath.Uart.Parity == (UINT8) Parity &&\r
361 mSerialDevicePath.Uart.StopBits == (UINT8) StopBits\r
362 ) {\r
363 gBS->RestoreTPL (Tpl);\r
364 return EFI_SUCCESS;\r
365 }\r
366\r
367 //\r
368 // Update the device path\r
369 //\r
370 mSerialDevicePath.Uart.BaudRate = BaudRate;\r
371 mSerialDevicePath.Uart.DataBits = DataBits;\r
372 mSerialDevicePath.Uart.Parity = (UINT8) Parity;\r
373 mSerialDevicePath.Uart.StopBits = (UINT8) StopBits;\r
374\r
375 Status = gBS->ReinstallProtocolInterface (\r
376 mSerialHandle,\r
377 &gEfiDevicePathProtocolGuid,\r
378 &mSerialDevicePath,\r
379 &mSerialDevicePath\r
380 );\r
381\r
382 gBS->RestoreTPL (Tpl);\r
383\r
384 return Status;\r
385}\r
386\r
387/**\r
388 Set the control bits on a serial device\r
389\r
390 @param This Protocol instance pointer.\r
391 @param Control Set the bits of Control that are settable.\r
392\r
393 @retval EFI_SUCCESS The new control bits were set on the serial device.\r
394 @retval EFI_UNSUPPORTED The serial device does not support this operation.\r
395 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
396\r
397**/\r
398EFI_STATUS\r
399EFIAPI\r
400SerialSetControl (\r
401 IN EFI_SERIAL_IO_PROTOCOL *This,\r
402 IN UINT32 Control\r
403 )\r
404{\r
405 return SerialPortSetControl (Control);\r
406}\r
407\r
408/**\r
409 Retrieves the status of the control bits on a serial device\r
410\r
411 @param This Protocol instance pointer.\r
412 @param Control A pointer to return the current Control signals from the serial device.\r
413\r
414 @retval EFI_SUCCESS The control bits were read from the serial device.\r
415 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.\r
416\r
417**/\r
418EFI_STATUS\r
419EFIAPI\r
420SerialGetControl (\r
421 IN EFI_SERIAL_IO_PROTOCOL *This,\r
422 OUT UINT32 *Control\r
423 )\r
424{\r
425 return SerialPortGetControl (Control);\r
426}\r
427\r
428/**\r
429 Writes data to a serial device.\r
430\r
431 @param This Protocol instance pointer.\r
432 @param BufferSize On input, the size of the Buffer. On output, the amount of\r
433 data actually written.\r
434 @param Buffer The buffer of data to write\r
435\r
436 @retval EFI_SUCCESS The data was written.\r
437 @retval EFI_DEVICE_ERROR The device reported an error.\r
438 @retval EFI_TIMEOUT The data write was stopped due to a timeout.\r
439\r
440**/\r
441EFI_STATUS\r
442EFIAPI\r
443SerialWrite (\r
444 IN EFI_SERIAL_IO_PROTOCOL *This,\r
445 IN OUT UINTN *BufferSize,\r
446 IN VOID *Buffer\r
447 )\r
448{\r
449 UINTN Count;\r
450\r
451 Count = SerialPortWrite (Buffer, *BufferSize);\r
452\r
453 if (Count != *BufferSize) {\r
454 *BufferSize = Count;\r
455 return EFI_TIMEOUT;\r
456 }\r
457\r
458 return EFI_SUCCESS;\r
459}\r
460\r
461/**\r
462 Reads data from a serial device.\r
463\r
464 @param This Protocol instance pointer.\r
465 @param BufferSize On input, the size of the Buffer. On output, the amount of\r
466 data returned in Buffer.\r
467 @param Buffer The buffer to return the data into.\r
468\r
469 @retval EFI_SUCCESS The data was read.\r
470 @retval EFI_DEVICE_ERROR The device reported an error.\r
471 @retval EFI_TIMEOUT The data write was stopped due to a timeout.\r
472\r
473**/\r
474EFI_STATUS\r
475EFIAPI\r
476SerialRead (\r
477 IN EFI_SERIAL_IO_PROTOCOL *This,\r
478 IN OUT UINTN *BufferSize,\r
479 OUT VOID *Buffer\r
480 )\r
481{\r
482 UINTN Count;\r
483 UINTN TimeOut;\r
484\r
485 Count = 0;\r
486\r
487 while (Count < *BufferSize) {\r
488 TimeOut = 0;\r
489 while (TimeOut < mSerialIoMode.Timeout) {\r
490 if (SerialPortPoll ()) {\r
491 break;\r
492 }\r
493 gBS->Stall (10);\r
494 TimeOut += 10;\r
495 }\r
496 if (TimeOut >= mSerialIoMode.Timeout) {\r
497 break;\r
498 }\r
499 SerialPortRead (Buffer, 1);\r
500 Count++;\r
501 Buffer = (VOID *) ((UINT8 *) Buffer + 1);\r
502 }\r
503\r
504 if (Count != *BufferSize) {\r
505 *BufferSize = Count;\r
506 return EFI_TIMEOUT;\r
507 }\r
508\r
509 return EFI_SUCCESS;\r
510}\r
511\r
512/**\r
513 Initialization for the Serial Io Protocol.\r
514\r
515 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
516 @param[in] SystemTable A pointer to the EFI System Table.\r
517\r
518 @retval EFI_SUCCESS The entry point is executed successfully.\r
519 @retval other Some error occurs when executing this entry point.\r
520\r
521**/\r
522EFI_STATUS\r
523EFIAPI\r
524SerialDxeInitialize (\r
525 IN EFI_HANDLE ImageHandle,\r
526 IN EFI_SYSTEM_TABLE *SystemTable\r
527 )\r
528{\r
529 EFI_STATUS Status;\r
530\r
531 mSerialIoMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
532 mSerialIoMode.DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits);\r
533 mSerialIoMode.Parity = (UINT32) PcdGet8 (PcdUartDefaultParity);\r
534 mSerialIoMode.StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits);\r
535 mSerialIoMode.ReceiveFifoDepth = PcdGet16 (PcdUartDefaultReceiveFifoDepth);\r
536 mSerialDevicePath.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);\r
537 mSerialDevicePath.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits);\r
538 mSerialDevicePath.Uart.Parity = PcdGet8 (PcdUartDefaultParity);\r
539 mSerialDevicePath.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits);\r
540\r
541 //\r
542 // Issue a reset to initialize the Serial Port\r
543 //\r
544 Status = mSerialIoTemplate.Reset (&mSerialIoTemplate);\r
545 if (EFI_ERROR (Status)) {\r
546 return Status;\r
547 }\r
548\r
549 //\r
550 // Make a new handle with Serial IO protocol and its device path on it.\r
551 //\r
552 Status = gBS->InstallMultipleProtocolInterfaces (\r
553 &mSerialHandle,\r
554 &gEfiSerialIoProtocolGuid, &mSerialIoTemplate,\r
555 &gEfiDevicePathProtocolGuid, &mSerialDevicePath,\r
556 NULL\r
557 );\r
558 ASSERT_EFI_ERROR (Status);\r
559\r
560 return Status;\r
561}\r
562\r