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