]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SerialDxe/SerialIo.c
19fc889c25aff4999d975c1b9d0a4f34ca5c1b08
[mirror_edk2.git] / MdeModulePkg / Universal / SerialDxe / SerialIo.c
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 is not functioning correctly.
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 //
185 // value field set in SerialDxeInitialize()?
186 //--------- ------------------- -----------------------------
187 0, // ControlMask
188 1000 * 1000, // Timeout
189 0, // BaudRate yes
190 1, // ReceiveFifoDepth
191 0, // DataBits yes
192 0, // Parity yes
193 0 // StopBits yes
194 };
195
196 EFI_SERIAL_IO_PROTOCOL mSerialIoTemplate = {
197 SERIAL_IO_INTERFACE_REVISION,
198 SerialReset,
199 SerialSetAttributes,
200 SerialSetControl,
201 SerialGetControl,
202 SerialWrite,
203 SerialRead,
204 &mSerialIoMode
205 };
206
207 /**
208 Reset the serial device.
209
210 @param This Protocol instance pointer.
211
212 @retval EFI_SUCCESS The device was reset.
213 @retval EFI_DEVICE_ERROR The serial device could not be reset.
214
215 **/
216 EFI_STATUS
217 EFIAPI
218 SerialReset (
219 IN EFI_SERIAL_IO_PROTOCOL *This
220 )
221 {
222 EFI_STATUS Status;
223
224 Status = SerialPortInitialize ();
225 if (EFI_ERROR (Status)) {
226 return Status;
227 }
228
229 //
230 // Go set the current attributes
231 //
232 Status = This->SetAttributes (
233 This,
234 This->Mode->BaudRate,
235 This->Mode->ReceiveFifoDepth,
236 This->Mode->Timeout,
237 (EFI_PARITY_TYPE) This->Mode->Parity,
238 (UINT8) This->Mode->DataBits,
239 (EFI_STOP_BITS_TYPE) This->Mode->StopBits
240 );
241
242 return Status;
243 }
244
245 /**
246 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
247 data bits, and stop bits on a serial device.
248
249 @param This Protocol instance pointer.
250 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the
251 device's default interface speed.
252 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
253 serial interface. A ReceiveFifoDepth value of 0 will use
254 the device's default FIFO depth.
255 @param Timeout The requested time out for a single character in microseconds.
256 This timeout applies to both the transmit and receive side of the
257 interface. A Timeout value of 0 will use the device's default time
258 out value.
259 @param Parity The type of parity to use on this serial device. A Parity value of
260 DefaultParity will use the device's default parity value.
261 @param DataBits The number of data bits to use on the serial device. A DataBits
262 value of 0 will use the device's default data bit setting.
263 @param StopBits The number of stop bits to use on this serial device. A StopBits
264 value of DefaultStopBits will use the device's default number of
265 stop bits.
266
267 @retval EFI_SUCCESS The device was reset.
268 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
269
270 **/
271 EFI_STATUS
272 EFIAPI
273 SerialSetAttributes (
274 IN EFI_SERIAL_IO_PROTOCOL *This,
275 IN UINT64 BaudRate,
276 IN UINT32 ReceiveFifoDepth,
277 IN UINT32 Timeout,
278 IN EFI_PARITY_TYPE Parity,
279 IN UINT8 DataBits,
280 IN EFI_STOP_BITS_TYPE StopBits
281 )
282 {
283 EFI_STATUS Status;
284 EFI_TPL Tpl;
285 UINT64 OriginalBaudRate;
286 UINT32 OriginalReceiveFifoDepth;
287 UINT32 OriginalTimeout;
288 EFI_PARITY_TYPE OriginalParity;
289 UINT8 OriginalDataBits;
290 EFI_STOP_BITS_TYPE OriginalStopBits;
291
292 //
293 // Preserve the original input values in case
294 // SerialPortSetAttributes() updates the input/output
295 // parameters even on error.
296 //
297 OriginalBaudRate = BaudRate;
298 OriginalReceiveFifoDepth = ReceiveFifoDepth;
299 OriginalTimeout = Timeout;
300 OriginalParity = Parity;
301 OriginalDataBits = DataBits;
302 OriginalStopBits = StopBits;
303 Status = SerialPortSetAttributes (&BaudRate, &ReceiveFifoDepth, &Timeout, &Parity, &DataBits, &StopBits);
304 if (EFI_ERROR (Status)) {
305 //
306 // If it is just to set Timeout value and unsupported is returned,
307 // do not return error.
308 //
309 if ((Status == EFI_UNSUPPORTED) &&
310 (This->Mode->Timeout != OriginalTimeout) &&
311 (This->Mode->ReceiveFifoDepth == OriginalReceiveFifoDepth) &&
312 (This->Mode->BaudRate == OriginalBaudRate) &&
313 (This->Mode->DataBits == (UINT32) OriginalDataBits) &&
314 (This->Mode->Parity == (UINT32) OriginalParity) &&
315 (This->Mode->StopBits == (UINT32) OriginalStopBits)) {
316 //
317 // Restore to the original input values.
318 //
319 BaudRate = OriginalBaudRate;
320 ReceiveFifoDepth = OriginalReceiveFifoDepth;
321 Timeout = OriginalTimeout;
322 Parity = OriginalParity;
323 DataBits = OriginalDataBits;
324 StopBits = OriginalStopBits;
325 Status = EFI_SUCCESS;
326 } else {
327 return Status;
328 }
329 }
330
331 //
332 // Set the Serial I/O mode and update the device path
333 //
334
335 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
336
337 //
338 // Set the Serial I/O mode
339 //
340 This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
341 This->Mode->Timeout = Timeout;
342 This->Mode->BaudRate = BaudRate;
343 This->Mode->DataBits = (UINT32) DataBits;
344 This->Mode->Parity = (UINT32) Parity;
345 This->Mode->StopBits = (UINT32) StopBits;
346
347 //
348 // Check if the device path has actually changed
349 //
350 if (mSerialDevicePath.Uart.BaudRate == BaudRate &&
351 mSerialDevicePath.Uart.DataBits == DataBits &&
352 mSerialDevicePath.Uart.Parity == (UINT8) Parity &&
353 mSerialDevicePath.Uart.StopBits == (UINT8) StopBits
354 ) {
355 gBS->RestoreTPL (Tpl);
356 return EFI_SUCCESS;
357 }
358
359 //
360 // Update the device path
361 //
362 mSerialDevicePath.Uart.BaudRate = BaudRate;
363 mSerialDevicePath.Uart.DataBits = DataBits;
364 mSerialDevicePath.Uart.Parity = (UINT8) Parity;
365 mSerialDevicePath.Uart.StopBits = (UINT8) StopBits;
366
367 Status = gBS->ReinstallProtocolInterface (
368 mSerialHandle,
369 &gEfiDevicePathProtocolGuid,
370 &mSerialDevicePath,
371 &mSerialDevicePath
372 );
373
374 gBS->RestoreTPL (Tpl);
375
376 return Status;
377 }
378
379 /**
380 Set the control bits on a serial device
381
382 @param This Protocol instance pointer.
383 @param Control Set the bits of Control that are settable.
384
385 @retval EFI_SUCCESS The new control bits were set on the serial device.
386 @retval EFI_UNSUPPORTED The serial device does not support this operation.
387 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
388
389 **/
390 EFI_STATUS
391 EFIAPI
392 SerialSetControl (
393 IN EFI_SERIAL_IO_PROTOCOL *This,
394 IN UINT32 Control
395 )
396 {
397 return SerialPortSetControl (Control);
398 }
399
400 /**
401 Retrieves the status of the control bits on a serial device
402
403 @param This Protocol instance pointer.
404 @param Control A pointer to return the current Control signals from the serial device.
405
406 @retval EFI_SUCCESS The control bits were read from the serial device.
407 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
408
409 **/
410 EFI_STATUS
411 EFIAPI
412 SerialGetControl (
413 IN EFI_SERIAL_IO_PROTOCOL *This,
414 OUT UINT32 *Control
415 )
416 {
417 return SerialPortGetControl (Control);
418 }
419
420 /**
421 Writes data to a serial device.
422
423 @param This Protocol instance pointer.
424 @param BufferSize On input, the size of the Buffer. On output, the amount of
425 data actually written.
426 @param Buffer The buffer of data to write
427
428 @retval EFI_SUCCESS The data was written.
429 @retval EFI_DEVICE_ERROR The device reported an error.
430 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
431
432 **/
433 EFI_STATUS
434 EFIAPI
435 SerialWrite (
436 IN EFI_SERIAL_IO_PROTOCOL *This,
437 IN OUT UINTN *BufferSize,
438 IN VOID *Buffer
439 )
440 {
441 UINTN Count;
442
443 Count = SerialPortWrite (Buffer, *BufferSize);
444
445 if (Count != *BufferSize) {
446 *BufferSize = Count;
447 return EFI_TIMEOUT;
448 }
449
450 return EFI_SUCCESS;
451 }
452
453 /**
454 Reads data from a serial device.
455
456 @param This Protocol instance pointer.
457 @param BufferSize On input, the size of the Buffer. On output, the amount of
458 data returned in Buffer.
459 @param Buffer The buffer to return the data into.
460
461 @retval EFI_SUCCESS The data was read.
462 @retval EFI_DEVICE_ERROR The device reported an error.
463 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
464
465 **/
466 EFI_STATUS
467 EFIAPI
468 SerialRead (
469 IN EFI_SERIAL_IO_PROTOCOL *This,
470 IN OUT UINTN *BufferSize,
471 OUT VOID *Buffer
472 )
473 {
474 UINTN Count;
475 UINTN TimeOut;
476
477 Count = 0;
478
479 while (Count < *BufferSize) {
480 TimeOut = 0;
481 while (TimeOut < mSerialIoMode.Timeout) {
482 if (SerialPortPoll ()) {
483 break;
484 }
485 gBS->Stall (10);
486 TimeOut += 10;
487 }
488 if (TimeOut >= mSerialIoMode.Timeout) {
489 break;
490 }
491 SerialPortRead (Buffer, 1);
492 Count++;
493 Buffer = (VOID *) ((UINT8 *) Buffer + 1);
494 }
495
496 if (Count != *BufferSize) {
497 *BufferSize = Count;
498 return EFI_TIMEOUT;
499 }
500
501 return EFI_SUCCESS;
502 }
503
504 /**
505 Initialization for the Serial Io Protocol.
506
507 @param[in] ImageHandle The firmware allocated handle for the EFI image.
508 @param[in] SystemTable A pointer to the EFI System Table.
509
510 @retval EFI_SUCCESS The entry point is executed successfully.
511 @retval other Some error occurs when executing this entry point.
512
513 **/
514 EFI_STATUS
515 EFIAPI
516 SerialDxeInitialize (
517 IN EFI_HANDLE ImageHandle,
518 IN EFI_SYSTEM_TABLE *SystemTable
519 )
520 {
521 EFI_STATUS Status;
522
523 mSerialIoMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
524 mSerialIoMode.DataBits = (UINT32) PcdGet8 (PcdUartDefaultDataBits);
525 mSerialIoMode.Parity = (UINT32) PcdGet8 (PcdUartDefaultParity);
526 mSerialIoMode.StopBits = (UINT32) PcdGet8 (PcdUartDefaultStopBits);
527 mSerialIoMode.ReceiveFifoDepth = PcdGet16 (PcdUartDefaultReceiveFifoDepth);
528 mSerialDevicePath.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
529 mSerialDevicePath.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits);
530 mSerialDevicePath.Uart.Parity = PcdGet8 (PcdUartDefaultParity);
531 mSerialDevicePath.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits);
532
533 //
534 // Issue a reset to initialize the Serial Port
535 //
536 Status = mSerialIoTemplate.Reset (&mSerialIoTemplate);
537 if (EFI_ERROR (Status)) {
538 return Status;
539 }
540
541 //
542 // Make a new handle with Serial IO protocol and its device path on it.
543 //
544 Status = gBS->InstallMultipleProtocolInterfaces (
545 &mSerialHandle,
546 &gEfiSerialIoProtocolGuid, &mSerialIoTemplate,
547 &gEfiDevicePathProtocolGuid, &mSerialDevicePath,
548 NULL
549 );
550 ASSERT_EFI_ERROR (Status);
551
552 return Status;
553 }
554