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