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