]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/UnixSerialIoDxe/UnixSerialIo.c
fa4e3aad362651fc3b27a8bf2dd7df64da80558a
[mirror_edk2.git] / UnixPkg / UnixSerialIoDxe / UnixSerialIo.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 UnixSerialIo.c
15
16 Abstract:
17
18 Our DriverBinding member functions operate on the handles
19 created by the NT Bus driver.
20
21 Handle(1) - UnixIo - DevicePath(1)
22
23 If a serial port is added to the system this driver creates a new handle.
24 The new handle is required, since the serial device must add an UART device
25 pathnode.
26
27 Handle(2) - SerialIo - DevicePath(1)\UART
28
29 The driver then adds a gEfiUnixSerialPortGuid as a protocol to Handle(1).
30 The instance data for this protocol is the private data used to create
31 Handle(2).
32
33 Handle(1) - UnixIo - DevicePath(1) - UnixSerialPort
34
35 If the driver is unloaded Handle(2) is removed from the system and
36 gEfiUnixSerialPortGuid is removed from Handle(1).
37
38 Note: Handle(1) is any handle created by the Win NT Bus driver that is passed
39 into the DriverBinding member functions of this driver. This driver requires
40 a Handle(1) to contain a UnixIo protocol, a DevicePath protocol, and
41 the TypeGuid in the UnixIo must be gEfiUnixSerialPortGuid.
42
43 If Handle(1) contains a gEfiUnixSerialPortGuid protocol then the driver is
44 loaded on the device.
45
46 --*/
47
48 #include "UnixSerialIo.h"
49 #include <termio.h>
50
51 EFI_DRIVER_BINDING_PROTOCOL gUnixSerialIoDriverBinding = {
52 UnixSerialIoDriverBindingSupported,
53 UnixSerialIoDriverBindingStart,
54 UnixSerialIoDriverBindingStop,
55 0xa,
56 NULL,
57 NULL
58 };
59
60 UINTN
61 ConvertBaud2Unix (
62 UINT64 BaudRate
63 )
64 {
65 switch (BaudRate) {
66 case 0:
67 return B0;
68 case 50:
69 return B50;
70 case 75:
71 return B75;
72 case 110:
73 return B110;
74 case 134:
75 return B134;
76 case 150:
77 return B150;
78 case 200:
79 return B200;
80 case 300:
81 return B300;
82 case 600:
83 return B600;
84 case 1200:
85 return B1200;
86 case 1800:
87 return B1800;
88 case 2400:
89 return B2400;
90 case 4800:
91 return B4800;
92 case 9600:
93 return B9600;
94 case 19200:
95 return B19200;
96 case 38400:
97 return B38400;
98 case 57600:
99 return B57600;
100 case 115200:
101 return B115200;
102 case 230400:
103 return B230400;
104 case 460800:
105 return B460800;
106 case 500000:
107 return B500000;
108 case 576000:
109 return B576000;
110 case 921600:
111 return B921600;
112 case 1000000:
113 return B1000000;
114 case 1152000:
115 return B1152000;
116 case 1500000:
117 return B1500000;
118 case 2000000:
119 return B2000000;
120 case 2500000:
121 return B2500000;
122 case 3000000:
123 return B3000000;
124 case 3500000:
125 return B3500000;
126 case 4000000:
127 return B4000000;
128 case __MAX_BAUD:
129 default:
130 DEBUG ((EFI_D_ERROR, "Invalid Baud Rate Parameter!\r\n"));
131 }
132 return -1;
133 }
134
135 UINTN
136 ConvertByteSize2Unix (
137 UINT8 DataBit
138 )
139 {
140 switch (DataBit) {
141 case 5:
142 return CS5;
143 case 6:
144 return CS6;
145 case 7:
146 return CS7;
147 case 8:
148 return CS8;
149 default:
150 DEBUG ((EFI_D_ERROR, "Invalid Data Size Parameter!\r\n"));
151 }
152 return -1;
153 }
154
155 VOID
156 ConvertParity2Unix (
157 struct termios *Options,
158 EFI_PARITY_TYPE Parity
159 )
160 {
161 switch (Parity) {
162 case NoParity:
163 Options->c_cflag &= ~PARENB;
164 break;
165 case EvenParity:
166 Options->c_cflag |= PARENB;
167 break;
168 case OddParity:
169 Options->c_cflag |= PARENB;
170 Options->c_cflag |= PARODD;
171 break;
172 case MarkParity:
173 Options->c_cflag = PARENB | CMSPAR | PARODD;
174 break;
175 case SpaceParity:
176 Options->c_cflag |= PARENB | CMSPAR;
177 Options->c_cflag &= ~PARODD;
178 break;
179 default:
180 DEBUG ((EFI_D_ERROR, "Invalid Parity Parameter!\r\n"));
181 }
182 }
183
184 VOID
185 ConvertStopBit2Unix (
186 struct termios *Options,
187 EFI_STOP_BITS_TYPE StopBits
188 )
189 {
190 switch (StopBits) {
191 case TwoStopBits:
192 Options->c_cflag |= CSTOPB;
193 break;
194 case OneStopBit:
195 case OneFiveStopBits:
196 case DefaultStopBits:
197 Options->c_cflag &= ~CSTOPB;
198 }
199 }
200
201 EFI_STATUS
202 EFIAPI
203 UnixSerialIoDriverBindingSupported (
204 IN EFI_DRIVER_BINDING_PROTOCOL *This,
205 IN EFI_HANDLE Handle,
206 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
207 )
208 /*++
209
210 Routine Description:
211 The implementation of EFI_DRIVER_BINDING_PROTOCOL.EFI_DRIVER_BINDING_SUPPORTED.
212
213 Arguments:
214
215 Returns:
216
217 None
218
219 --*/
220 {
221 EFI_STATUS Status;
222 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
223 EFI_UNIX_IO_PROTOCOL *UnixIo;
224 UART_DEVICE_PATH *UartNode;
225
226 //
227 // Open the IO Abstraction(s) needed to perform the supported test
228 //
229 Status = gBS->OpenProtocol (
230 Handle,
231 &gEfiDevicePathProtocolGuid,
232 (VOID**)&ParentDevicePath,
233 This->DriverBindingHandle,
234 Handle,
235 EFI_OPEN_PROTOCOL_BY_DRIVER
236 );
237 if (Status == EFI_ALREADY_STARTED) {
238 return EFI_SUCCESS;
239 }
240
241 if (EFI_ERROR (Status)) {
242 return Status;
243 }
244
245 gBS->CloseProtocol (
246 Handle,
247 &gEfiDevicePathProtocolGuid,
248 This->DriverBindingHandle,
249 Handle
250 );
251
252 Status = gBS->OpenProtocol (
253 Handle,
254 &gEfiUnixIoProtocolGuid,
255 (VOID**)&UnixIo,
256 This->DriverBindingHandle,
257 Handle,
258 EFI_OPEN_PROTOCOL_BY_DRIVER
259 );
260 if (Status == EFI_ALREADY_STARTED) {
261 return EFI_SUCCESS;
262 }
263
264 if (EFI_ERROR (Status)) {
265 return Status;
266 }
267
268 //
269 // Make sure that the Unix Thunk Protocol is valid
270 //
271 if (UnixIo->UnixThunk->Signature != EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) {
272 Status = EFI_UNSUPPORTED;
273 goto Error;
274 }
275
276 //
277 // Check the GUID to see if this is a handle type the driver supports
278 //
279 if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixSerialPortGuid)) {
280 Status = EFI_UNSUPPORTED;
281 goto Error;
282 }
283
284 if (RemainingDevicePath != NULL) {
285 Status = EFI_UNSUPPORTED;
286 UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
287 if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
288 UartNode->Header.SubType != MSG_UART_DP ||
289 DevicePathNodeLength((EFI_DEVICE_PATH_PROTOCOL *)UartNode) != sizeof(UART_DEVICE_PATH)) {
290 goto Error;
291 }
292 if (UartNode->BaudRate < 0 || UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
293 goto Error;
294 }
295 if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
296 goto Error;
297 }
298 if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
299 goto Error;
300 }
301 if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
302 goto Error;
303 }
304 if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
305 goto Error;
306 }
307 if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
308 goto Error;
309 }
310 Status = EFI_SUCCESS;
311 }
312
313 Error:
314 //
315 // Close the I/O Abstraction(s) used to perform the supported test
316 //
317 gBS->CloseProtocol (
318 Handle,
319 &gEfiUnixIoProtocolGuid,
320 This->DriverBindingHandle,
321 Handle
322 );
323
324 return Status;
325 }
326
327 EFI_STATUS
328 EFIAPI
329 UnixSerialIoDriverBindingStart (
330 IN EFI_DRIVER_BINDING_PROTOCOL *This,
331 IN EFI_HANDLE Handle,
332 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
333 )
334 /*++
335
336 Routine Description:
337
338 Arguments:
339
340 Returns:
341
342 None
343
344 --*/
345 {
346 EFI_STATUS Status;
347 EFI_UNIX_IO_PROTOCOL *UnixIo;
348 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
349 UINTN UnixHandle;
350 UART_DEVICE_PATH Node;
351 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
352 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
353 UINTN EntryCount;
354 UINTN Index;
355 EFI_SERIAL_IO_PROTOCOL *SerialIo;
356 CHAR8 AsciiDevName[1024];
357
358 DEBUG ((EFI_D_INFO, "SerialIo drive binding start!\r\n"));
359 Private = NULL;
360 UnixHandle = -1;
361
362 //
363 // Grab the protocols we need
364 //
365 Status = gBS->OpenProtocol (
366 Handle,
367 &gEfiDevicePathProtocolGuid,
368 (VOID**)&ParentDevicePath,
369 This->DriverBindingHandle,
370 Handle,
371 EFI_OPEN_PROTOCOL_BY_DRIVER
372 );
373 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
374 return Status;
375 }
376
377 //
378 // Grab the IO abstraction we need to get any work done
379 //
380 Status = gBS->OpenProtocol (
381 Handle,
382 &gEfiUnixIoProtocolGuid,
383 (VOID**)&UnixIo,
384 This->DriverBindingHandle,
385 Handle,
386 EFI_OPEN_PROTOCOL_BY_DRIVER
387 );
388 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
389 gBS->CloseProtocol (
390 Handle,
391 &gEfiDevicePathProtocolGuid,
392 This->DriverBindingHandle,
393 Handle
394 );
395 return Status;
396 }
397
398 if (Status == EFI_ALREADY_STARTED) {
399
400 if (RemainingDevicePath == NULL) {
401 return EFI_SUCCESS;
402 }
403
404 //
405 // Make sure a child handle does not already exist. This driver can only
406 // produce one child per serial port.
407 //
408 Status = gBS->OpenProtocolInformation (
409 Handle,
410 &gEfiUnixIoProtocolGuid,
411 &OpenInfoBuffer,
412 &EntryCount
413 );
414 if (EFI_ERROR (Status)) {
415 return Status;
416 }
417
418 Status = EFI_ALREADY_STARTED;
419 for (Index = 0; Index < EntryCount; Index++) {
420 if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
421 Status = gBS->OpenProtocol (
422 OpenInfoBuffer[Index].ControllerHandle,
423 &gEfiSerialIoProtocolGuid,
424 (VOID**)&SerialIo,
425 This->DriverBindingHandle,
426 Handle,
427 EFI_OPEN_PROTOCOL_GET_PROTOCOL
428 );
429 if (!EFI_ERROR (Status)) {
430 CopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
431 Status = SerialIo->SetAttributes (
432 SerialIo,
433 Node.BaudRate,
434 SerialIo->Mode->ReceiveFifoDepth,
435 SerialIo->Mode->Timeout,
436 Node.Parity,
437 Node.DataBits,
438 Node.StopBits
439 );
440 }
441 break;
442 }
443 }
444
445 FreePool (OpenInfoBuffer);
446 return Status;
447 }
448
449 //
450 // Check to see if we can access the hardware device. If it's Open in Unix we
451 // will not get access.
452 //
453 UnicodeStrToAsciiStr(UnixIo->EnvString, AsciiDevName);
454 UnixHandle = UnixIo->UnixThunk->Open (AsciiDevName, O_RDWR | O_NOCTTY, 0);
455
456 if (UnixHandle == -1) {
457 DEBUG ((EFI_D_INFO, "Faile to open serial device, %s!\r\n", UnixIo->EnvString ));
458 UnixIo->UnixThunk->Perror (AsciiDevName);
459 Status = EFI_DEVICE_ERROR;
460 goto Error;
461 }
462 DEBUG ((EFI_D_INFO, "Success to open serial device %s, Hanle = 0x%x \r\n", UnixIo->EnvString, UnixHandle));
463
464 //
465 // Construct Private data
466 //
467 Private = AllocatePool (sizeof (UNIX_SERIAL_IO_PRIVATE_DATA));
468 if (Private == NULL) {
469 goto Error;
470 }
471
472 //
473 // This signature must be valid before any member function is called
474 //
475 Private->Signature = UNIX_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
476 Private->UnixHandle = UnixHandle;
477 Private->ControllerHandle = Handle;
478 Private->Handle = NULL;
479 Private->UnixThunk = UnixIo->UnixThunk;
480 Private->ParentDevicePath = ParentDevicePath;
481 Private->ControllerNameTable = NULL;
482
483 Private->SoftwareLoopbackEnable = FALSE;
484 Private->HardwareLoopbackEnable = FALSE;
485 Private->HardwareFlowControl = FALSE;
486 Private->Fifo.First = 0;
487 Private->Fifo.Last = 0;
488 Private->Fifo.Surplus = SERIAL_MAX_BUFFER_SIZE;
489
490 AddUnicodeString (
491 "eng",
492 gUnixSerialIoComponentName.SupportedLanguages,
493 &Private->ControllerNameTable,
494 UnixIo->EnvString
495 );
496
497 Private->SerialIo.Revision = SERIAL_IO_INTERFACE_REVISION;
498 Private->SerialIo.Reset = UnixSerialIoReset;
499 Private->SerialIo.SetAttributes = UnixSerialIoSetAttributes;
500 Private->SerialIo.SetControl = UnixSerialIoSetControl;
501 Private->SerialIo.GetControl = UnixSerialIoGetControl;
502 Private->SerialIo.Write = UnixSerialIoWrite;
503 Private->SerialIo.Read = UnixSerialIoRead;
504 Private->SerialIo.Mode = &Private->SerialIoMode;
505
506 if (RemainingDevicePath != NULL) {
507 //
508 // Match the configuration of the RemainingDevicePath. IsHandleSupported()
509 // already checked to make sure the RemainingDevicePath contains settings
510 // that we can support.
511 //
512 CopyMem (&Private->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
513 } else {
514 //
515 // Build the device path by appending the UART node to the ParentDevicePath
516 // from the UnixIo handle. The Uart setings are zero here, since
517 // SetAttribute() will update them to match the default setings.
518 //
519 ZeroMem (&Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
520 Private->UartDevicePath.Header.Type = MESSAGING_DEVICE_PATH;
521 Private->UartDevicePath.Header.SubType = MSG_UART_DP;
522 SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
523 }
524
525 //
526 // Build the device path by appending the UART node to the ParentDevicePath
527 // from the UnixIo handle. The Uart setings are zero here, since
528 // SetAttribute() will update them to match the current setings.
529 //
530 Private->DevicePath = AppendDevicePathNode (
531 ParentDevicePath,
532 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
533 );
534 if (Private->DevicePath == NULL) {
535 Status = EFI_OUT_OF_RESOURCES;
536 goto Error;
537 }
538
539 //
540 // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
541 //
542 Private->SerialIoMode.ControlMask = SERIAL_CONTROL_MASK;
543 Private->SerialIoMode.Timeout = SERIAL_TIMEOUT_DEFAULT;
544 Private->SerialIoMode.BaudRate = Private->UartDevicePath.BaudRate;
545 Private->SerialIoMode.ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
546 Private->SerialIoMode.DataBits = Private->UartDevicePath.DataBits;
547 Private->SerialIoMode.Parity = Private->UartDevicePath.Parity;
548 Private->SerialIoMode.StopBits = Private->UartDevicePath.StopBits;
549
550 //
551 // Issue a reset to initialize the COM port
552 //
553 Status = Private->SerialIo.Reset (&Private->SerialIo);
554 if (EFI_ERROR (Status)) {
555 goto Error;
556 }
557
558 //
559 // Create new child handle
560 //
561 Status = gBS->InstallMultipleProtocolInterfaces (
562 &Private->Handle,
563 &gEfiSerialIoProtocolGuid,
564 &Private->SerialIo,
565 &gEfiDevicePathProtocolGuid,
566 Private->DevicePath,
567 NULL
568 );
569 if (EFI_ERROR (Status)) {
570 goto Error;
571 }
572
573 //
574 // Open For Child Device
575 //
576 Status = gBS->OpenProtocol (
577 Handle,
578 &gEfiUnixIoProtocolGuid,
579 (VOID**)&UnixIo,
580 This->DriverBindingHandle,
581 Private->Handle,
582 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
583 );
584 if (EFI_ERROR (Status)) {
585 goto Error;
586 }
587
588 return EFI_SUCCESS;
589
590 Error:
591 //
592 // Use the Stop() function to free all resources allocated in Start()
593 //
594 if (Private != NULL) {
595 if (Private->Handle != NULL) {
596 This->Stop (This, Handle, 1, &Private->Handle);
597 } else {
598 if (UnixHandle != -1) {
599 Private->UnixThunk->Close (UnixHandle);
600 }
601
602 if (Private->DevicePath != NULL) {
603 FreePool (Private->DevicePath);
604 }
605
606 FreeUnicodeStringTable (Private->ControllerNameTable);
607
608 FreePool (Private);
609 }
610 }
611
612 This->Stop (This, Handle, 0, NULL);
613
614 return Status;
615 }
616
617 EFI_STATUS
618 EFIAPI
619 UnixSerialIoDriverBindingStop (
620 IN EFI_DRIVER_BINDING_PROTOCOL *This,
621 IN EFI_HANDLE Handle,
622 IN UINTN NumberOfChildren,
623 IN EFI_HANDLE *ChildHandleBuffer
624 )
625 /*++
626
627 Routine Description:
628
629 TODO: Add function description
630
631 Arguments:
632
633 This - TODO: add argument description
634 Handle - TODO: add argument description
635 NumberOfChildren - TODO: add argument description
636 ChildHandleBuffer - TODO: add argument description
637
638 Returns:
639
640 EFI_DEVICE_ERROR - TODO: Add description for return value
641 EFI_SUCCESS - TODO: Add description for return value
642
643 --*/
644 {
645 EFI_STATUS Status;
646 UINTN Index;
647 BOOLEAN AllChildrenStopped;
648 EFI_SERIAL_IO_PROTOCOL *SerialIo;
649 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
650 EFI_UNIX_IO_PROTOCOL *UnixIo;
651
652 //
653 // Complete all outstanding transactions to Controller.
654 // Don't allow any new transaction to Controller to be started.
655 //
656
657 if (NumberOfChildren == 0) {
658 //
659 // Close the bus driver
660 //
661 Status = gBS->CloseProtocol (
662 Handle,
663 &gEfiUnixIoProtocolGuid,
664 This->DriverBindingHandle,
665 Handle
666 );
667 Status = gBS->CloseProtocol (
668 Handle,
669 &gEfiDevicePathProtocolGuid,
670 This->DriverBindingHandle,
671 Handle
672 );
673 return Status;
674 }
675
676 AllChildrenStopped = TRUE;
677
678 for (Index = 0; Index < NumberOfChildren; Index++) {
679 Status = gBS->OpenProtocol (
680 ChildHandleBuffer[Index],
681 &gEfiSerialIoProtocolGuid,
682 (VOID**)&SerialIo,
683 This->DriverBindingHandle,
684 Handle,
685 EFI_OPEN_PROTOCOL_GET_PROTOCOL
686 );
687 if (!EFI_ERROR (Status)) {
688 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (SerialIo);
689
690 ASSERT (Private->Handle == ChildHandleBuffer[Index]);
691
692 Status = gBS->CloseProtocol (
693 Handle,
694 &gEfiUnixIoProtocolGuid,
695 This->DriverBindingHandle,
696 ChildHandleBuffer[Index]
697 );
698
699 Status = gBS->UninstallMultipleProtocolInterfaces (
700 ChildHandleBuffer[Index],
701 &gEfiSerialIoProtocolGuid,
702 &Private->SerialIo,
703 &gEfiDevicePathProtocolGuid,
704 Private->DevicePath,
705 NULL
706 );
707
708 if (EFI_ERROR (Status)) {
709 gBS->OpenProtocol (
710 Handle,
711 &gEfiUnixIoProtocolGuid,
712 (VOID **) &UnixIo,
713 This->DriverBindingHandle,
714 ChildHandleBuffer[Index],
715 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
716 );
717 } else {
718 Private->UnixThunk->Close (Private->UnixHandle);
719
720 FreePool (Private->DevicePath);
721
722 FreeUnicodeStringTable (Private->ControllerNameTable);
723
724 FreePool (Private);
725 }
726 }
727
728 if (EFI_ERROR (Status)) {
729 AllChildrenStopped = FALSE;
730 }
731 }
732
733 if (!AllChildrenStopped) {
734 return EFI_DEVICE_ERROR;
735 }
736
737 return EFI_SUCCESS;
738 }
739
740 //
741 // Serial IO Protocol member functions
742 //
743
744 EFI_STATUS
745 EFIAPI
746 UnixSerialIoReset (
747 IN EFI_SERIAL_IO_PROTOCOL *This
748 )
749 /*++
750
751 Routine Description:
752
753 TODO: Add function description
754
755 Arguments:
756
757 This - TODO: add argument description
758
759 Returns:
760
761 TODO: add return values
762
763 --*/
764 {
765 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
766 EFI_TPL Tpl;
767 UINTN UnixStatus;
768
769 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
770
771 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
772
773 UnixStatus = Private->UnixThunk->Tcflush (
774 Private->UnixHandle,
775 TCIOFLUSH
776 );
777 switch (UnixStatus) {
778 case EBADF:
779 DEBUG ((EFI_D_ERROR, "Invalid handle of serial device!\r\n"));
780 return EFI_DEVICE_ERROR;
781 case EINVAL:
782 DEBUG ((EFI_D_ERROR, "Invalid queue selector!\r\n"));
783 return EFI_DEVICE_ERROR;
784 case ENOTTY:
785 DEBUG ((EFI_D_ERROR, "The file associated with serial's handle is not a terminal!\r\n"));
786 return EFI_DEVICE_ERROR;
787 default:
788 DEBUG ((EFI_D_ERROR, "The serial IO device is reset successfully!\r\n"));
789 }
790
791 gBS->RestoreTPL (Tpl);
792
793 return This->SetAttributes (
794 This,
795 This->Mode->BaudRate,
796 This->Mode->ReceiveFifoDepth,
797 This->Mode->Timeout,
798 This->Mode->Parity,
799 (UINT8) This->Mode->DataBits,
800 This->Mode->StopBits
801 );
802 }
803
804 EFI_STATUS
805 EFIAPI
806 UnixSerialIoSetAttributes (
807 IN EFI_SERIAL_IO_PROTOCOL *This,
808 IN UINT64 BaudRate,
809 IN UINT32 ReceiveFifoDepth,
810 IN UINT32 Timeout,
811 IN EFI_PARITY_TYPE Parity,
812 IN UINT8 DataBits,
813 IN EFI_STOP_BITS_TYPE StopBits
814 )
815 /*++
816
817 Routine Description:
818
819 This function is used to set the attributes.
820
821 Arguments:
822
823 This - A pointer to the EFI_SERIAL_IO_PROTOCOL structrue.
824 BaudRate - The Baud rate of the serial device.
825 ReceiveFifoDepth - The request depth of fifo on receive side.
826 Timeout - the request timeout for a single charact.
827 Parity - The type of parity used in serial device.
828 DataBits - Number of deata bits used in serial device.
829 StopBits - Number of stop bits used in serial device.
830
831 Returns:
832 Status code
833
834 None
835
836 --*/
837 {
838 EFI_STATUS Status;
839 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
840 EFI_TPL Tpl;
841 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
842
843 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
844 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
845
846 //
847 // Some of our arguments have defaults if a null value is passed in, and
848 // we must set the default values if a null argument is passed in.
849 //
850 if (BaudRate == 0) {
851 BaudRate = SERIAL_BAUD_DEFAULT;
852 }
853
854 if (ReceiveFifoDepth == 0) {
855 ReceiveFifoDepth = SERIAL_FIFO_DEFAULT;
856 }
857
858 if (Timeout == 0) {
859 Timeout = SERIAL_TIMEOUT_DEFAULT;
860 }
861
862 if (Parity == DefaultParity) {
863 Parity = NoParity;
864 }
865
866 if (DataBits == 0) {
867 DataBits = SERIAL_DATABITS_DEFAULT;
868 }
869
870 if (StopBits == DefaultStopBits) {
871 StopBits = OneStopBit;
872 }
873
874 //
875 // See if the new attributes already match the current attributes
876 //
877 if (Private->UartDevicePath.BaudRate == BaudRate &&
878 Private->UartDevicePath.DataBits == DataBits &&
879 Private->UartDevicePath.Parity == Parity &&
880 Private->UartDevicePath.StopBits == StopBits &&
881 Private->SerialIoMode.ReceiveFifoDepth == ReceiveFifoDepth &&
882 Private->SerialIoMode.Timeout == Timeout ) {
883 gBS->RestoreTPL(Tpl);
884 return EFI_SUCCESS;
885 }
886
887 //
888 // Try to get options from serial device.
889 //
890 if (Private->UnixThunk->Tcgetattr (Private->UnixHandle, &Private->UnixTermios) == -1) {
891 Private->UnixThunk->Perror ("IoSetAttributes");
892 gBS->RestoreTPL (Tpl);
893 return EFI_DEVICE_ERROR;
894 }
895
896 //
897 // Setting Baud Rate
898 //
899 Private->UnixThunk->Cfsetispeed (&Private->UnixTermios, ConvertBaud2Unix(BaudRate));
900 Private->UnixThunk->Cfsetospeed (&Private->UnixTermios, ConvertBaud2Unix(BaudRate));
901 //
902 // Setting DataBits
903 //
904 Private->UnixTermios.c_cflag &= ~CSIZE;
905 Private->UnixTermios.c_cflag |= ConvertByteSize2Unix (DataBits);
906 //
907 // Setting Parity
908 //
909 ConvertParity2Unix (&Private->UnixTermios, Parity);
910 //
911 // Setting StopBits
912 //
913 ConvertStopBit2Unix (&Private->UnixTermios, StopBits);
914 //
915 // Raw input
916 //
917 Private->UnixTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
918 //
919 // Raw output
920 //
921 Private->UnixTermios.c_oflag &= ~OPOST;
922 //
923 // Support hardware flow control
924 //
925 Private->UnixTermios.c_cflag &= ~CRTSCTS;;
926 //
927 // Time out
928 //
929 Private->UnixTermios.c_cc[VMIN] = 0;
930 Private->UnixTermios.c_cc[VTIME] = (Timeout/1000000) * 10;
931
932 //
933 // Set the options
934 //
935 if (-1 == Private->UnixThunk->Tcsetattr (
936 Private->UnixHandle,
937 TCSANOW,
938 &Private->UnixTermios
939 )) {
940 DEBUG ((EFI_D_INFO, "Fail to set options for serial device!\r\n"));
941 return EFI_DEVICE_ERROR;
942 }
943
944 //
945 // Update mode
946 //
947 Private->SerialIoMode.BaudRate = BaudRate;
948 Private->SerialIoMode.ReceiveFifoDepth = ReceiveFifoDepth;
949 Private->SerialIoMode.Timeout = Timeout;
950 Private->SerialIoMode.Parity = Parity;
951 Private->SerialIoMode.DataBits = DataBits;
952 Private->SerialIoMode.StopBits = StopBits;
953 //
954 // See if Device Path Node has actually changed
955 //
956 if (Private->UartDevicePath.BaudRate == BaudRate &&
957 Private->UartDevicePath.DataBits == DataBits &&
958 Private->UartDevicePath.Parity == Parity &&
959 Private->UartDevicePath.StopBits == StopBits ) {
960 gBS->RestoreTPL(Tpl);
961 return EFI_SUCCESS;
962 }
963
964 //
965 // Update the device path
966 //
967 Private->UartDevicePath.BaudRate = BaudRate;
968 Private->UartDevicePath.DataBits = DataBits;
969 Private->UartDevicePath.Parity = (UINT8) Parity;
970 Private->UartDevicePath.StopBits = (UINT8) StopBits;
971
972 NewDevicePath = AppendDevicePathNode (
973 Private->ParentDevicePath,
974 (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
975 );
976 if (NewDevicePath == NULL) {
977 gBS->RestoreTPL (Tpl);
978 return EFI_DEVICE_ERROR;
979 }
980
981 if (Private->Handle != NULL) {
982 Status = gBS->ReinstallProtocolInterface (
983 Private->Handle,
984 &gEfiDevicePathProtocolGuid,
985 Private->DevicePath,
986 NewDevicePath
987 );
988 if (EFI_ERROR (Status)) {
989 gBS->RestoreTPL (Tpl);
990 return Status;
991 }
992 }
993
994 if (Private->DevicePath != NULL) {
995 FreePool (Private->DevicePath);
996 }
997
998 Private->DevicePath = NewDevicePath;
999
1000 gBS->RestoreTPL (Tpl);
1001
1002 return EFI_SUCCESS;
1003 }
1004
1005 EFI_STATUS
1006 EFIAPI
1007 UnixSerialIoSetControl (
1008 IN EFI_SERIAL_IO_PROTOCOL *This,
1009 IN UINT32 Control
1010 )
1011 /*++
1012
1013 Routine Description:
1014
1015 TODO: Add function description
1016
1017 Arguments:
1018
1019 This - TODO: add argument description
1020 Control - TODO: add argument description
1021
1022 Returns:
1023
1024 EFI_DEVICE_ERROR - TODO: Add description for return value
1025 EFI_DEVICE_ERROR - TODO: Add description for return value
1026 EFI_SUCCESS - TODO: Add description for return value
1027
1028 --*/
1029 {
1030 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1031 UINTN Result;
1032 UINTN Status;
1033 struct termios Options;
1034 EFI_TPL Tpl;
1035
1036 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1037
1038 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1039
1040 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMGET, &Status);
1041
1042 if (Result == -1) {
1043 Private->UnixThunk->Perror ("SerialSetControl");
1044 gBS->RestoreTPL (Tpl);
1045 return EFI_DEVICE_ERROR;
1046 }
1047
1048 Private->HardwareFlowControl = FALSE;
1049 Private->SoftwareLoopbackEnable = FALSE;
1050 Private->HardwareLoopbackEnable = FALSE;
1051
1052 if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
1053 Options.c_cflag |= TIOCM_RTS;
1054 }
1055
1056 if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
1057 Options.c_cflag |= TIOCM_DTR;
1058 }
1059
1060 if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
1061 Private->HardwareFlowControl = TRUE;
1062 }
1063
1064 if (Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
1065 Private->SoftwareLoopbackEnable = TRUE;
1066 }
1067
1068 if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
1069 Private->HardwareLoopbackEnable = TRUE;
1070 }
1071
1072 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMSET, &Status);
1073
1074 if (Result == -1) {
1075 Private->UnixThunk->Perror ("SerialSetControl");
1076 gBS->RestoreTPL (Tpl);
1077 return EFI_DEVICE_ERROR;
1078 }
1079
1080 gBS->RestoreTPL (Tpl);
1081
1082 return EFI_SUCCESS;
1083 }
1084
1085 EFI_STATUS
1086 EFIAPI
1087 UnixSerialIoGetControl (
1088 IN EFI_SERIAL_IO_PROTOCOL *This,
1089 OUT UINT32 *Control
1090 )
1091 /*++
1092
1093 Routine Description:
1094
1095 TODO: Add function description
1096
1097 Arguments:
1098
1099 This - TODO: add argument description
1100 Control - TODO: add argument description
1101
1102 Returns:
1103
1104 EFI_DEVICE_ERROR - TODO: Add description for return value
1105 EFI_DEVICE_ERROR - TODO: Add description for return value
1106 EFI_DEVICE_ERROR - TODO: Add description for return value
1107 EFI_SUCCESS - TODO: Add description for return value
1108
1109 --*/
1110 {
1111 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1112 UINTN Result;
1113 UINTN Status;
1114 UINT32 Bits;
1115 EFI_TPL Tpl;
1116 UINTN Bytes;
1117
1118 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1119
1120 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1121 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, TIOCMGET, &Status);
1122 if (Result == -1) {
1123 Private->UnixThunk->Perror ("SerialGetControl");
1124 gBS->RestoreTPL (Tpl);
1125 return EFI_DEVICE_ERROR;
1126 }
1127
1128 if ((Status & TIOCM_CTS) == TIOCM_CTS) {
1129 Bits |= EFI_SERIAL_CLEAR_TO_SEND;
1130 }
1131
1132 if ((Status & TIOCM_DSR) == TIOCM_DSR) {
1133 Bits |= EFI_SERIAL_DATA_SET_READY;
1134 }
1135
1136 if ((Status & TIOCM_DTR) == TIOCM_DTR) {
1137 Bits |= EFI_SERIAL_DATA_TERMINAL_READY;
1138 }
1139
1140 if ((Status & TIOCM_RTS) == TIOCM_RTS) {
1141 Bits |= EFI_SERIAL_REQUEST_TO_SEND;
1142 }
1143
1144 if ((Status & TIOCM_RNG) == TIOCM_RNG) {
1145 Bits |= EFI_SERIAL_RING_INDICATE;
1146 }
1147
1148 if ((Status & TIOCM_CAR) == TIOCM_CAR) {
1149 Bits |= EFI_SERIAL_CARRIER_DETECT;
1150 }
1151
1152 if (Private->HardwareFlowControl) {
1153 Bits |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
1154 }
1155
1156 if (Private->SoftwareLoopbackEnable) {
1157 Bits |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
1158 }
1159
1160 if (Private->HardwareLoopbackEnable) {
1161 Bits |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
1162 }
1163
1164 Result = Private->UnixThunk->IoCtl (Private->UnixHandle, FIONREAD, &Bytes);
1165 if (Result == -1) {
1166 Private->UnixThunk->Perror ("SerialGetControl");
1167 gBS->RestoreTPL (Tpl);
1168 return EFI_DEVICE_ERROR;
1169 }
1170
1171 if (Bytes == 0) {
1172 Bits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
1173 }
1174
1175 *Control = Bits;
1176
1177 gBS->RestoreTPL (Tpl);
1178
1179 return EFI_SUCCESS;
1180 }
1181
1182 EFI_STATUS
1183 EFIAPI
1184 UnixSerialIoWrite (
1185 IN EFI_SERIAL_IO_PROTOCOL *This,
1186 IN OUT UINTN *BufferSize,
1187 IN VOID *Buffer
1188 )
1189 /*++
1190
1191 Routine Description:
1192
1193 TODO: Add function description
1194
1195 Arguments:
1196
1197 This - TODO: add argument description
1198 BufferSize - TODO: add argument description
1199 Buffer - TODO: add argument description
1200
1201 Returns:
1202
1203 EFI_DEVICE_ERROR - TODO: Add description for return value
1204 EFI_SUCCESS - TODO: Add description for return value
1205
1206 --*/
1207 {
1208 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1209 UINT8 *ByteBuffer;
1210 UINT32 TotalBytesWritten;
1211 UINT32 BytesToGo;
1212 UINT32 BytesWritten;
1213 UINT32 Index;
1214 UINT32 Control;
1215 EFI_TPL Tpl;
1216
1217 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1218
1219 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1220
1221 ByteBuffer = (UINT8 *) Buffer;
1222 TotalBytesWritten = 0;
1223
1224 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1225 for (Index = 0; Index < *BufferSize; Index++) {
1226 if (IsaSerialFifoAdd (&Private->Fifo, ByteBuffer[Index]) == EFI_SUCCESS) {
1227 TotalBytesWritten++;
1228 } else {
1229 break;
1230 }
1231 }
1232 } else {
1233 BytesToGo = (*BufferSize);
1234
1235 do {
1236 if (Private->HardwareFlowControl) {
1237 //
1238 // Send RTS
1239 //
1240 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1241 Control |= EFI_SERIAL_REQUEST_TO_SEND;
1242 UnixSerialIoSetControl (&Private->SerialIo, Control);
1243 }
1244
1245 //
1246 // Do the write
1247 //
1248 BytesWritten = Private->UnixThunk->Write (
1249 Private->UnixHandle,
1250 &ByteBuffer[TotalBytesWritten],
1251 BytesToGo
1252 );
1253
1254 if (Private->HardwareFlowControl) {
1255 //
1256 // Assert RTS
1257 //
1258 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1259 Control &= ~ (UINT32) EFI_SERIAL_REQUEST_TO_SEND;
1260 UnixSerialIoSetControl (&Private->SerialIo, Control);
1261 }
1262
1263 TotalBytesWritten += BytesWritten;
1264 BytesToGo -= BytesWritten;
1265 } while (BytesToGo > 0);
1266 }
1267
1268 *BufferSize = TotalBytesWritten;
1269
1270 gBS->RestoreTPL (Tpl);
1271
1272 return EFI_SUCCESS;
1273 }
1274
1275 EFI_STATUS
1276 EFIAPI
1277 UnixSerialIoRead (
1278 IN EFI_SERIAL_IO_PROTOCOL *This,
1279 IN OUT UINTN *BufferSize,
1280 OUT VOID *Buffer
1281 )
1282 /*++
1283
1284 Routine Description:
1285
1286 TODO: Add function description
1287
1288 Arguments:
1289
1290 This - TODO: add argument description
1291 BufferSize - TODO: add argument description
1292 Buffer - TODO: add argument description
1293
1294 Returns:
1295
1296 EFI_DEVICE_ERROR - TODO: Add description for return value
1297
1298 --*/
1299 {
1300 UNIX_SERIAL_IO_PRIVATE_DATA *Private;
1301 UINT32 BytesRead;
1302 EFI_STATUS Status;
1303 UINT32 Index;
1304 UINT8 Data;
1305 UINT32 Control;
1306 EFI_TPL Tpl;
1307
1308 Tpl = gBS->RaiseTPL (TPL_NOTIFY);
1309
1310 Private = UNIX_SERIAL_IO_PRIVATE_DATA_FROM_THIS (This);
1311
1312 //
1313 // Do the read
1314 //
1315 if (Private->SoftwareLoopbackEnable || Private->HardwareLoopbackEnable) {
1316 for (Index = 0, BytesRead = 0; Index < *BufferSize; Index++) {
1317 if (IsaSerialFifoRemove (&Private->Fifo, &Data) == EFI_SUCCESS) {
1318 ((UINT8 *) Buffer)[Index] = Data;
1319 BytesRead++;
1320 } else {
1321 break;
1322 }
1323 }
1324 } else {
1325 if (Private->HardwareFlowControl) {
1326 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1327 Control |= EFI_SERIAL_DATA_TERMINAL_READY;
1328 UnixSerialIoSetControl (&Private->SerialIo, Control);
1329 }
1330
1331 BytesRead = Private->UnixThunk->Read (Private->UnixHandle, Buffer, *BufferSize);
1332 if (Private->HardwareFlowControl) {
1333 UnixSerialIoGetControl (&Private->SerialIo, &Control);
1334 Control &= ~ (UINT32) EFI_SERIAL_DATA_TERMINAL_READY;
1335 UnixSerialIoSetControl (&Private->SerialIo, Control);
1336 }
1337
1338 }
1339
1340 if (BytesRead != *BufferSize) {
1341 Status = EFI_TIMEOUT;
1342 } else {
1343 Status = EFI_SUCCESS;
1344 }
1345
1346 *BufferSize = (UINTN) BytesRead;
1347
1348 gBS->RestoreTPL (Tpl);
1349
1350 return Status;
1351 }
1352
1353 BOOLEAN
1354 IsaSerialFifoFull (
1355 IN SERIAL_DEV_FIFO *Fifo
1356 )
1357 /*++
1358
1359 Routine Description:
1360 Detect whether specific FIFO is full or not
1361
1362 Arguments:
1363 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1364
1365 Returns:
1366 TRUE: the FIFO is full
1367 FALSE: the FIFO is not full
1368
1369 --*/
1370 {
1371 if (Fifo->Surplus == 0) {
1372 return TRUE;
1373 }
1374
1375 return FALSE;
1376 }
1377
1378 BOOLEAN
1379 IsaSerialFifoEmpty (
1380 IN SERIAL_DEV_FIFO *Fifo
1381 )
1382 /*++
1383
1384 Routine Description:
1385 Detect whether specific FIFO is empty or not
1386
1387 Arguments:
1388 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1389
1390 Returns:
1391 TRUE: the FIFO is empty
1392 FALSE: the FIFO is not empty
1393
1394 --*/
1395 {
1396 if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
1397 return TRUE;
1398 }
1399
1400 return FALSE;
1401 }
1402
1403 EFI_STATUS
1404 IsaSerialFifoAdd (
1405 IN SERIAL_DEV_FIFO *Fifo,
1406 IN UINT8 Data
1407 )
1408 /*++
1409
1410 Routine Description:
1411 Add data to specific FIFO
1412
1413 Arguments:
1414 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1415 Data UINT8: the data added to FIFO
1416
1417 Returns:
1418 EFI_SUCCESS: Add data to specific FIFO successfully
1419 EFI_OUT_RESOURCE: Failed to add data because FIFO is already full
1420
1421 --*/
1422 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1423 {
1424 //
1425 // if FIFO full can not add data
1426 //
1427 if (IsaSerialFifoFull (Fifo)) {
1428 return EFI_OUT_OF_RESOURCES;
1429 }
1430
1431 //
1432 // FIFO is not full can add data
1433 //
1434 Fifo->Data[Fifo->Last] = Data;
1435 Fifo->Surplus--;
1436 Fifo->Last++;
1437 if (Fifo->Last >= SERIAL_MAX_BUFFER_SIZE) {
1438 Fifo->Last = 0;
1439 }
1440
1441 return EFI_SUCCESS;
1442 }
1443
1444 EFI_STATUS
1445 IsaSerialFifoRemove (
1446 IN SERIAL_DEV_FIFO *Fifo,
1447 OUT UINT8 *Data
1448 )
1449 /*++
1450
1451 Routine Description:
1452 Remove data from specific FIFO
1453
1454 Arguments:
1455 Fifo SERIAL_DEV_FIFO *: A pointer to the Data Structure SERIAL_DEV_FIFO
1456 Data UINT8*: the data removed from FIFO
1457
1458 Returns:
1459 EFI_SUCCESS: Remove data from specific FIFO successfully
1460 EFI_OUT_RESOURCE: Failed to remove data because FIFO is empty
1461
1462 --*/
1463 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1464 {
1465 //
1466 // if FIFO is empty, no data can remove
1467 //
1468 if (IsaSerialFifoEmpty (Fifo)) {
1469 return EFI_OUT_OF_RESOURCES;
1470 }
1471
1472 //
1473 // FIFO is not empty, can remove data
1474 //
1475 *Data = Fifo->Data[Fifo->First];
1476 Fifo->Surplus++;
1477 Fifo->First++;
1478 if (Fifo->First >= SERIAL_MAX_BUFFER_SIZE) {
1479 Fifo->First = 0;
1480 }
1481
1482 return EFI_SUCCESS;
1483 }