]> git.proxmox.com Git - mirror_edk2.git/commitdiff
StdLib: Add terminal type line editing (Interactive IO) for console devices.
authordarylm503 <darylm503@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 11 Dec 2012 21:19:14 +0000 (21:19 +0000)
committerdarylm503 <darylm503@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 11 Dec 2012 21:19:14 +0000 (21:19 +0000)
Adds a subset of the terminal I/O capabilities described in the Single Unix Specification, V4.
Supports:
    Erase previous character.  Default is Backspace or ^H
    Erase line.  Default is ^U
TAB characters are supported and, by default, are rendered as 8 spaces.  They will still be read as a single TAB character.
Both Canonical and Non-Canonical modes are supported.
If a terminal device is opened with O_TTY_INIT in the mode, the device will be initialized to "sane" values for interactive use.  It will be in Canonical mode, Enter will be translated to NewLine and on output, a NewLine is translated to CRLF.  Echoing will be on, control characters are output as ^X, and TABs are expanded.
See the new <sys/termios.h> file for more information.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: daryl.mcdaniel@intel.com
Reviewed-by: erik.c.bjorge@intel.com
Reviewed-by: leroy.p.leahy@intel.com
Reviewed-by: lee.g.rosenbaum@intel.com
Reviewed-by: jaben.carsey@intel.com
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13989 6f19259b-4bc3-4df7-8a09-765794883524

23 files changed:
StdLib/Include/Containers/Fifo.h [new file with mode: 0644]
StdLib/Include/Containers/ModuloUtil.h [new file with mode: 0644]
StdLib/Include/sys/termios.h
StdLib/LibC/Containers/Common/ModuloUtil.c [new file with mode: 0644]
StdLib/LibC/Containers/ContainerLib.inf [new file with mode: 0644]
StdLib/LibC/Containers/Queues/Fifo.c [new file with mode: 0644]
StdLib/LibC/Main/Main.c
StdLib/LibC/Uefi/Devices/Console/daConsole.c
StdLib/LibC/Uefi/Devices/Utility/DevGenisis.c
StdLib/LibC/Uefi/Devices/daConsole.inf
StdLib/LibC/Uefi/InteractiveIO/CanonRead.c [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/IIO.c [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/IIO.inf [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/IIOecho.c [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c [new file with mode: 0644]
StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c [new file with mode: 0644]
StdLib/LibC/Uefi/SysCalls.c
StdLib/StdLib.dsc
StdLib/StdLib.inc

diff --git a/StdLib/Include/Containers/Fifo.h b/StdLib/Include/Containers/Fifo.h
new file mode 100644 (file)
index 0000000..3b232fe
--- /dev/null
@@ -0,0 +1,206 @@
+/** @file\r
+  Class for arbitrary sized FIFO queues.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#ifndef _FIFO_CLASS_H\r
+#define _FIFO_CLASS_H\r
+#include  <Uefi.h>\r
+#include  <wchar.h>\r
+#include  <Containers/ModuloUtil.h>\r
+#include  <sys/types.h>\r
+\r
+__BEGIN_DECLS\r
+\r
+typedef struct _FIFO_CLASS  cFIFO;\r
+\r
+/// Constants to select what is counted by the FIFO_NumInQueue function.\r
+typedef enum {\r
+  AsElements,     ///< Count the number of readable elements in the queue.\r
+  AsBytes         ///< Count the number of readable bytes in the queue.\r
+} FIFO_ElemBytes;\r
+\r
+/** Construct a new instance of a FIFO Queue.\r
+\r
+    @param[in]    NumElements   Number of elements to be contained in the new FIFO.\r
+    @param[in]    ElementSize   Size, in bytes, of an element\r
+\r
+    @retval   NULL      Unable to create the instance.\r
+    @retval   NonNULL   Pointer to the new FIFO instance.\r
+**/\r
+cFIFO * EFIAPI New_cFIFO(UINT32 NumElements, size_t ElementSize);\r
+\r
+/** Add one or more elements to the FIFO.\r
+\r
+    This function allows one to add one or more elements, as specified by Count,\r
+    to the FIFO.  Each element is of the size specified when the FIFO object\r
+    was instantiated (FIFO.ElementSize).\r
+\r
+    pElement points to the first byte of the first element to be added.\r
+    If multiple elements are to be added, the elements are expected to be\r
+    organized as a packed array.\r
+\r
+    @param[in]    Self        Pointer to the FIFO instance.\r
+    @param[in]    pElement    Pointer to the element(s) to enqueue (add).\r
+    @param[in]    Count       Number of elements to add.\r
+\r
+    @retval   0       The FIFO is full.\r
+    @retval   >=0     The number of elements added to the FIFO.\r
+**/\r
+typedef size_t  (EFIAPI *cFIFO_Enqueue) (cFIFO *Self, const void *ElementPointer, size_t Count);\r
+\r
+/** Read or copy elements from the FIFO.\r
+\r
+    This function allows one to read one or more elements, as specified by Count,\r
+    from the FIFO.  Each element is of the size specified when the FIFO object\r
+    was instantiated (FIFO.ElementSize).\r
+\r
+    pElement points to the destination of the first byte of the first element\r
+    to be read. If multiple elements are to be read, the elements are expected\r
+    to be organized as a packed array.\r
+\r
+    @param[in]    Self        Pointer to the FIFO instance.\r
+    @param[out]   pElement    Pointer to where to store the element(s) read from the FIFO.\r
+    @param[in]    Count       Number of elements to dequeue.\r
+    @param[in]    Consume     If TRUE, consume read elements.  Otherwise, preserve.\r
+\r
+    @retval   0       The FIFO is empty.\r
+    @retval   >=0     The number of elements read from the FIFO.\r
+**/\r
+typedef size_t  (EFIAPI *cFIFO_Dequeue) (cFIFO *Self, void *ElementPointer, size_t Count);\r
+\r
+/** Make a copy of the FIFO's data.\r
+    The contents of the FIFO is copied out and linearized without affecting the\r
+    FIFO contents.\r
+\r
+    @param[in]    Self              Pointer to the FIFO instance.\r
+    @param[out]   ElementPointer    Pointer to where to store the elements copied from the FIFO.\r
+    @param[in]    Count             Number of elements to copy.\r
+\r
+    @retval   0       The FIFO is empty.\r
+    @retval   >=0     The number of elements copied from the FIFO.\r
+**/\r
+typedef size_t  (EFIAPI *cFIFO_Copy) (cFIFO *Self, void *ElementPointer, size_t Count);\r
+\r
+/** Test whether the FIFO is empty.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+\r
+    @retval   TRUE    The FIFO is empty.\r
+    @retval   FALSE   The FIFO is NOT empty.\r
+**/\r
+typedef BOOLEAN     (EFIAPI *cFIFO_IsEmpty) (cFIFO *Self);\r
+\r
+/** Test whether the FIFO is full.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+\r
+    @retval   TRUE    The FIFO is full.\r
+    @retval   FALSE   The FIFO is NOT full.\r
+**/\r
+typedef BOOLEAN     (EFIAPI *cFIFO_IsFull)  (cFIFO *Self);\r
+\r
+/** Determine number of items available to read from the FIFO.\r
+\r
+    The number of items are either the number of bytes, or the number of elements\r
+    depending upon the value of the As enumerator.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+    @param[in]    As        An enumeration variable whose value determines whether the\r
+                            returned value is the number of bytes or the number of elements\r
+                            currently contained by the FIFO.\r
+\r
+    @retval   0       The FIFO is empty.\r
+    @retval   >=0     The number of items contained in the FIFO.\r
+**/\r
+typedef size_t      (EFIAPI *cFIFO_NumInQueue) (cFIFO *Self, FIFO_ElemBytes As);\r
+\r
+/** Determine amount of free space in the FIFO that can be written into.\r
+\r
+    The number of items are either the number of bytes, or the number of elements\r
+    depending upon the value of the As enumerator.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+    @param[in]    As        An enumeration variable whose value determines whether the\r
+                            returned value is the number of bytes or the number of elements\r
+                            currently available in the FIFO.\r
+\r
+    @retval   0       The FIFO is full.\r
+    @retval   >=0     The number of items which can be accepted by the FIFO.\r
+**/\r
+typedef size_t      (EFIAPI *cFIFO_FreeSpace) (cFIFO *Self, FIFO_ElemBytes As);\r
+\r
+/** Empty the FIFO, discarding up to NumToFlush elements.\r
+\r
+    @param[in]    Self              Pointer to the FIFO instance.\r
+    @param[in]    NumToFlush        Number of elements to flush from the FIFO.\r
+                                    If larger than the number of elements in the\r
+                                    FIFO, the FIFO is emptied.\r
+\r
+    @return     Returns the number of elements remaining in the FIFO after the flush.\r
+**/\r
+typedef size_t     (EFIAPI *cFIFO_Flush)   (cFIFO *Self, size_t NumToFlush);\r
+\r
+/** Remove the most recent element from the FIFO.\r
+\r
+    @param[in]    Self              Pointer to the FIFO instance.\r
+**/\r
+typedef void        (EFIAPI *cFIFO_Truncate)  (cFIFO *Self);\r
+\r
+/** Cleanly delete a FIFO instance.\r
+\r
+    @param[in]    Self              Pointer to the FIFO instance.\r
+**/\r
+typedef void        (EFIAPI *cFIFO_Delete)  (cFIFO *Self);\r
+\r
+/** Get the FIFO's current Read Index.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+\r
+    @return   The current value of the FIFO's ReadIndex member is returned.\r
+**/\r
+typedef UINT32      (EFIAPI *cFIFO_GetRDex) (cFIFO *Self);\r
+\r
+/** Get the FIFO's current Write Index.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+\r
+    @return   The current value of the FIFO's WriteIndex member is returned.\r
+**/\r
+typedef UINT32      (EFIAPI *cFIFO_GetWDex) (cFIFO *Self);\r
+\r
+/// Structure declaration for FIFO objects.\r
+struct _FIFO_CLASS {\r
+  /* ######## Public Functions ######## */\r
+  cFIFO_Enqueue     Write;            ///< Write an element into the FIFO.\r
+  cFIFO_Dequeue     Read;             ///< Read an element from the FIFO.\r
+  cFIFO_Copy        Copy;             ///< Non-destructive copy from FIFO.\r
+  cFIFO_IsEmpty     IsEmpty;          ///< Test whether the FIFO is empty.\r
+  cFIFO_IsFull      IsFull;           ///< Test whether the FIFO is full.\r
+  cFIFO_NumInQueue  Count;            ///< Return the number of elements contained in the FIFO.\r
+  cFIFO_FreeSpace   FreeSpace;        ///< Return the number of available elements in the FIFO.\r
+  cFIFO_Flush       Flush;            ///< Remove the N earliest elements from the FIFO.\r
+  cFIFO_Truncate    Truncate;         ///< Remove the most recent element from the FIFO.\r
+  cFIFO_Delete      Delete;           ///< Delete the FIFO object.\r
+\r
+  /* ######## Protected Functions ######## */\r
+  cFIFO_GetRDex     GetRDex;          ///< Get a copy of the current Read Index.\r
+  cFIFO_GetWDex     GetWDex;          ///< Get a copy of the current Write Index.\r
+\r
+  /* ######## PRIVATE Data ######## */\r
+  void             *Queue;            ///< The FIFO's data storage.\r
+  UINT32            ElementSize;      ///< Number of bytes in an element.\r
+  UINT32            NumElements;      ///< Number of elements the FIFO can store.\r
+  UINT32            ReadIndex;        ///< Index of next element to Read.\r
+  UINT32            WriteIndex;       ///< Index of where next element will be Written.\r
+};\r
+\r
+__END_DECLS\r
+#endif  /* _FIFO_CLASS_H */\r
diff --git a/StdLib/Include/Containers/ModuloUtil.h b/StdLib/Include/Containers/ModuloUtil.h
new file mode 100644 (file)
index 0000000..f98ab0a
--- /dev/null
@@ -0,0 +1,105 @@
+/** @file\r
+  Utility functions for performing basic math operations constrained within a\r
+  modulus.\r
+\r
+  These functions are intended to simplify small changes to a value which much\r
+  remain within a specified modulus.  Changes must be less than or equal to\r
+  the modulus specified by MaxVal.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#ifndef _MODULO_UTIL_H\r
+#define _MODULO_UTIL_H\r
+#include  <Uefi.h>\r
+#include  <sys/EfiCdefs.h>\r
+\r
+__BEGIN_DECLS\r
+\r
+/** Counter = (Counter + 1) % MaxVal;\r
+\r
+    Counter is always expected to be LESS THAN MaxVal.\r
+        0 <= Counter < MaxVal\r
+\r
+    @param[in]    Counter   The value to be incremented.\r
+    @param[in]    MaxVal    Modulus of the operation.\r
+\r
+    @return   Returns the result of incrementing Counter, modulus MaxVal.\r
+              If Counter >= MaxVal, returns -1.\r
+**/\r
+INT32\r
+EFIAPI\r
+ModuloIncrement(\r
+  UINT32  Counter,\r
+  UINT32  MaxVal\r
+  );\r
+\r
+/** Counter = (Counter - 1) % MaxVal;\r
+\r
+    Counter is always expected to be LESS THAN MaxVal.\r
+        0 <= Counter < MaxVal\r
+\r
+    @param[in]    Counter   The value to be decremented.\r
+    @param[in]    MaxVal    Modulus of the operation.\r
+\r
+    @return   Returns the result of decrementing Counter, modulus MaxVal.\r
+              If Counter >= MaxVal, returns -1.\r
+**/\r
+INT32\r
+EFIAPI\r
+ModuloDecrement(\r
+  UINT32  Counter,\r
+  UINT32  MaxVal\r
+  );\r
+\r
+/** Counter = (Counter + Increment) % MaxVal;\r
+\r
+    @param[in]    Counter   The value to be incremented.\r
+    @param[in]    Increment The value to add to Counter.\r
+    @param[in]    MaxVal    Modulus of the operation.\r
+\r
+    @return   Returns the result of adding Increment to Counter, modulus MaxVal,\r
+              or -1 if Increment is larger than MaxVal.\r
+**/\r
+INT32\r
+EFIAPI\r
+ModuloAdd (\r
+  UINT32  Counter,\r
+  UINT32  Increment,\r
+  UINT32  MaxVal\r
+  );\r
+\r
+/** Increment Counter but don't increment past MaxVal.\r
+\r
+    @param[in]    Counter   The value to be decremented.\r
+    @param[in]    MaxVal    The upper bound for Counter.  Counter < MaxVal.\r
+\r
+    @return   Returns the result of incrementing Counter.\r
+**/\r
+UINT32\r
+EFIAPI\r
+BoundIncrement(\r
+  UINT32  Counter,\r
+  UINT32  MaxVal\r
+  );\r
+\r
+/** Decrement Counter but don't decrement past zero.\r
+\r
+    @param[in]    Counter   The value to be decremented.\r
+\r
+    @return   Returns the result of decrementing Counter.\r
+**/\r
+UINT32\r
+EFIAPI\r
+BoundDecrement(\r
+  UINT32  Counter\r
+  );\r
+\r
+__END_DECLS\r
+#endif  /* _MODULO_UTIL_H */\r
index 13e15d2fad4888bcef6ed7ced92ee8a184525f0d..e144d521f58b97838abc4a375092c339a209bc23 100644 (file)
@@ -215,19 +215,171 @@ struct termios {
 #include <sys/EfiCdefs.h>\r
 \r
 __BEGIN_DECLS\r
+\r
+/** Get input baud rate.\r
+\r
+    Extracts the input baud rate from the termios structure pointed to by the\r
+    pTermios argument.\r
+\r
+    @param[in]  pTermios  A pointer to the termios structure from which to extract\r
+                          the input baud rate.\r
+\r
+    @return The value of the input speed is returned exactly as it is contained\r
+            in the termios structure, without interpretation.\r
+**/\r
 speed_t cfgetispeed (const struct termios *);\r
+\r
+/** Get output baud rate.\r
+\r
+    Extracts the output baud rate from the termios structure pointed to by the\r
+    pTermios argument.\r
+\r
+    @param[in]  pTermios  A pointer to the termios structure from which to extract\r
+                          the output baud rate.\r
+\r
+    @return The value of the output speed is returned exactly as it is contained\r
+            in the termios structure, without interpretation.\r
+**/\r
 speed_t cfgetospeed (const struct termios *);\r
+\r
+/** Set input baud rate.\r
+\r
+    Replaces the input baud rate, in the termios structure pointed to by the\r
+    pTermios argument, with the value of NewSpeed.\r
+\r
+    @param[out]   pTermios  A pointer to the termios structure into which to set\r
+                            the input baud rate.\r
+    @param[in]    NewSpeed  The new input baud rate.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EINVAL - The value of NewSpeed is outside the range of\r
+                      possible speed values as specified in <sys/termios.h>.\r
+**/\r
 int     cfsetispeed (struct termios *, speed_t);\r
+\r
+/** Set output baud rate.\r
+\r
+    Replaces the output baud rate, in the termios structure pointed to by the\r
+    pTermios argument, with the value of NewSpeed.\r
+\r
+    @param[out]   pTermios  A pointer to the termios structure into which to set\r
+                            the output baud rate.\r
+    @param[in]    NewSpeed  The new output baud rate.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EINVAL - The value of NewSpeed is outside the range of\r
+                      possible speed values as specified in <sys/termios.h>.\r
+**/\r
 int     cfsetospeed (struct termios *, speed_t);\r
+\r
+/** Get the parameters associated with an interactive IO device.\r
+\r
+    Get the parameters associated with the device referred to by\r
+    fd and store them into the termios structure referenced by pTermios.\r
+\r
+    @param[in]    fd        The file descriptor for an open interactive IO device.\r
+    @param[out]   pTermios  A pointer to a termios structure into which to store\r
+                            attributes of the interactive IO device.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EBADF - The fd argument is not a valid file descriptor.\r
+                    * ENOTTY - The file associated with fd is not an interactive IO device.\r
+**/\r
 int     tcgetattr   (int, struct termios *);\r
+\r
+/** Set the parameters associated with an interactive IO device.\r
+\r
+    Set the parameters associated with the device referred to by\r
+    fd to the values in the termios structure referenced by pTermios.\r
+\r
+    Behavior is modified by the value of the OptAct parameter:\r
+      * TCSANOW: The change shall occur immediately.\r
+      * TCSADRAIN: The change shall occur after all output written to fd is\r
+        transmitted. This action should be used when changing parameters which\r
+        affect output.\r
+      * TCSAFLUSH: The change shall occur after all output written to fd is\r
+        transmitted, and all input so far received but not read shall be\r
+        discarded before the change is made.\r
+\r
+    @param[in]  fd        The file descriptor for an open interactive IO device.\r
+    @param[in]  OptAct    Currently has no effect.\r
+    @param[in]  pTermios  A pointer to a termios structure into which to retrieve\r
+                          attributes to set in the interactive IO device.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EBADF - The fd argument is not a valid file descriptor.\r
+                    * ENOTTY - The file associated with fd is not an interactive IO device.\r
+**/\r
 int     tcsetattr   (int, int, const struct termios *);\r
+\r
+/** Transmit pending output.\r
+\r
+\r
+    @param[in]  fd        The file descriptor for an open interactive IO device.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EBADF - The fd argument is not a valid file descriptor.\r
+                    * ENOTTY - The file associated with fd is not an interactive IO device.\r
+                    * EINTR - A signal interrupted tcdrain().\r
+                    * ENOTSUP - This function is not supported.\r
+**/\r
 int     tcdrain     (int);\r
+\r
+/** Suspend or restart the transmission or reception of data.\r
+\r
+    This function will suspend or resume transmission or reception of data on\r
+    the file referred to by fd, depending on the value of Action.\r
+\r
+    @param[in]  fd        The file descriptor of an open interactive IO device (terminal).\r
+    @param[in]  Action    The action to be performed:\r
+                            * TCOOFF - Suspend output.\r
+                            * TCOON - Resume suspended output.\r
+                            * TCIOFF - If fd refers to an IIO device, transmit a\r
+                                      STOP character, which is intended to cause the\r
+                                      terminal device to stop transmitting data.\r
+                            * TCION - If fd refers to an IIO device, transmit a\r
+                                      START character, which is intended to cause the\r
+                                      terminal device to start transmitting data.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EBADF - The fd argument is not a valid file descriptor.\r
+                    * ENOTTY - The file associated with fd is not an interactive IO device.\r
+                    * EINVAL - The Action argument is not a supported value.\r
+                    * ENOTSUP - This function is not supported.\r
+**/\r
 int     tcflow      (int, int);\r
+\r
+/** Discard non-transmitted output data, non-read input data, or both.\r
+\r
+\r
+    @param[in]  fd              The file descriptor for an open interactive IO device.\r
+    @param[in]  QueueSelector   The IO queue to be affected:\r
+                                  * TCIFLUSH - If fd refers to a device open for input, flush\r
+                                    pending input.  Otherwise error EINVAL.\r
+                                  * TCOFLUSH - If fd refers to a device open for output,\r
+                                    flush pending output.  Otherwise error EINVAL.\r
+                                  * TCIOFLUSH - If fd refers to a device open for both\r
+                                    input and output, flush pending input and output.\r
+                                    Otherwise error EINVAL.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EBADF - The fd argument is not a valid file descriptor.\r
+                    * ENOTTY - The file associated with fd is not an interactive IO device.\r
+                    * EINVAL - The QueueSelector argument is not a supported value.\r
+                    * ENOTSUP - This function is not supported.\r
+**/\r
 int     tcflush     (int, int);\r
+\r
 //int     tcsendbreak (int, int);\r
 //pid_t   tcgetsid    (int);\r
 \r
-\r
 //void    cfmakeraw   (struct termios *);\r
 //int     cfsetspeed  (struct termios *, speed_t);\r
 __END_DECLS\r
diff --git a/StdLib/LibC/Containers/Common/ModuloUtil.c b/StdLib/LibC/Containers/Common/ModuloUtil.c
new file mode 100644 (file)
index 0000000..5f75698
--- /dev/null
@@ -0,0 +1,149 @@
+/** @file\r
+    Utility functions for performing basic math operations constrained within a\r
+    modulus.\r
+\r
+    These functions are intended to simplify small changes to a value which much\r
+    remain within a specified modulus.\r
+\r
+  NOTE: Changes must be less than or equal to the modulus specified by MaxVal.\r
+\r
+    Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+    This program and the accompanying materials are licensed and made available\r
+    under the terms and conditions of the BSD License which accompanies this\r
+    distribution.  The full text of the license may be found at\r
+    http://opensource.org/licenses/bsd-license.php.\r
+\r
+    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+#include  <LibConfig.h>\r
+#include  <assert.h>\r
+\r
+/** Counter = (Counter + 1) % MaxVal;\r
+\r
+    Counter is always expected to be LESS THAN MaxVal.\r
+        0 <= Counter < MaxVal\r
+\r
+    @param[in]    Counter   The value to be incremented.\r
+    @param[in]    MaxVal    Modulus of the operation.\r
+\r
+    @return   Returns the result of incrementing Counter, modulus MaxVal.\r
+              If Counter >= MaxVal, returns -1.\r
+**/\r
+INT32\r
+EFIAPI\r
+ModuloIncrement(\r
+  UINT32  Counter,\r
+  UINT32  MaxVal\r
+  )\r
+{\r
+  INT32  Temp;\r
+\r
+  if(Counter < MaxVal) {\r
+    Temp = (INT32)(Counter + 1);\r
+    if(Temp >= (INT32)MaxVal) {\r
+      Temp = 0;\r
+    }\r
+  }\r
+  else {\r
+    Temp = -1;\r
+  }\r
+  return Temp;\r
+}\r
+\r
+/** Counter = (Counter - 1) % MaxVal;\r
+\r
+    Counter is always expected to be LESS THAN MaxVal.\r
+        0 <= Counter < MaxVal\r
+\r
+    @param[in]    Counter   The value to be decremented.\r
+    @param[in]    MaxVal    Modulus of the operation.\r
+\r
+    @return   Returns the result of decrementing Counter, modulus MaxVal.\r
+              If Counter >= MaxVal, returns -1.\r
+**/\r
+INT32\r
+EFIAPI\r
+ModuloDecrement(\r
+  UINT32  Counter,\r
+  UINT32  MaxVal\r
+  )\r
+{\r
+  INT32  Temp;\r
+\r
+  if(Counter < MaxVal) {\r
+    Temp = (INT32)Counter - 1;\r
+    // If Counter is zero, Temp will become -1.\r
+    if(Temp < 0) {\r
+      Temp = (INT32)MaxVal - 1;\r
+    }\r
+  }\r
+  else {\r
+    Temp = -1;\r
+  }\r
+\r
+  return Temp;\r
+}\r
+\r
+/** Decrement Counter but don't decrement past zero.\r
+\r
+    @param[in]    Counter   The value to be decremented.\r
+\r
+    @return   Returns the result of decrementing Counter.\r
+**/\r
+UINT32\r
+EFIAPI\r
+BoundDecrement(\r
+  UINT32  Counter\r
+  )\r
+{\r
+  return ((Counter > 0) ? (Counter - 1) : 0);\r
+}\r
+\r
+/** Increment Counter but don't increment past MaxVal.\r
+    Counter should be maintained in the range (0 <= Counter < MaxVal).\r
+\r
+    @param[in]    Counter   The value to be decremented.\r
+    @param[in]    MaxVal    The upper bound for Counter.\r
+\r
+    @return   Returns the result of incrementing Counter.\r
+**/\r
+UINT32\r
+EFIAPI\r
+BoundIncrement(\r
+  UINT32  Counter,\r
+  UINT32  MaxVal\r
+  )\r
+{\r
+  return ((Counter < (MaxVal - 1)) ? (Counter + 1) : (MaxVal - 1));\r
+}\r
+\r
+/** Counter = (Counter + Increment) % MaxVal;\r
+\r
+    @param[in]    Counter   The value to be incremented.\r
+    @param[in]    Increment The value to add to Counter.\r
+    @param[in]    MaxVal    Modulus of the operation.\r
+\r
+    @return   Returns the result of adding Increment to Counter, modulus MaxVal,\r
+              or -1 if Increment is larger than MaxVal.\r
+**/\r
+INT32\r
+EFIAPI\r
+ModuloAdd (\r
+  UINT32  Counter,\r
+  UINT32  Increment,\r
+  UINT32  MaxVal\r
+  )\r
+{\r
+  UINT32   Temp;\r
+\r
+  if(Increment > MaxVal) {\r
+    return -1;\r
+  }\r
+  Temp = (Counter + Increment);\r
+  while(Temp >= MaxVal) {\r
+    Temp -= MaxVal;\r
+  }\r
+  return Temp;\r
+}\r
diff --git a/StdLib/LibC/Containers/ContainerLib.inf b/StdLib/LibC/Containers/ContainerLib.inf
new file mode 100644 (file)
index 0000000..4ca6690
--- /dev/null
@@ -0,0 +1,46 @@
+## @file\r
+# INF file for building the Container library.\r
+#\r
+# Various types of containers are implemented within this library.\r
+# Types of containers may be Queues (FIFO, LIFO, etc.), hash tables, etc.\r
+#\r
+# Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THIS PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = LibContainer\r
+  FILE_GUID                      = 92f7436e-7395-4da1-a7be-f352f0bcd79c\r
+  MODULE_TYPE                    = UEFI_APPLICATION\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = LibContainer\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  Queues/Fifo.c\r
+  Common/ModuloUtil.c\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  MemoryAllocationLib\r
+  LibC\r
+  LibWchar\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  StdLib/StdLib.dec\r
+  StdLibPrivateInternalFiles/DoNotUse.dec\r
diff --git a/StdLib/LibC/Containers/Queues/Fifo.c b/StdLib/LibC/Containers/Queues/Fifo.c
new file mode 100644 (file)
index 0000000..347ac02
--- /dev/null
@@ -0,0 +1,526 @@
+/** @file\r
+  Class for arbitrary sized FIFO queues.\r
+\r
+  The FIFO is empty if both the Read and Write indexes are equal.\r
+  The FIFO is full if the next write would make the Read and Write indexes equal.\r
+\r
+  Member variable NumElements is the maximum number of elements that can be\r
+  contained in the FIFO.\r
+    If NumElements is ZERO, there is an error.\r
+    NumElements should be in the range 1:N.\r
+\r
+  Members WriteIndex and ReadIndex are indexes into the array implementing the\r
+  FIFO.  They should be in the range 0:(NumElements - 1).\r
+\r
+  One element of the FIFO is always reserved as the "terminator" element.  Thus,\r
+  the capacity of a FIFO is actually NumElements-1.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+#include  <Library/BaseLib.h>\r
+#include  <Library/BaseMemoryLib.h>\r
+#include  <Library/MemoryAllocationLib.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <assert.h>\r
+#include  <errno.h>\r
+#include  <stdlib.h>\r
+#include  <stdint.h>\r
+#include  <wchar.h>\r
+#include  <Containers/Fifo.h>\r
+\r
+/** Determine number of items available to read from the FIFO.\r
+\r
+    The number of items are either the number of bytes, or the number of elements\r
+    depending upon the value of the As enumerator.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+    @param[in]    As        An enumeration variable whose value determines whether the\r
+                            returned value is the number of bytes or the number of elements\r
+                            currently contained by the FIFO.\r
+\r
+    @retval   0       The FIFO is empty.\r
+    @retval   >=0     The number of items contained by the FIFO.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_NumInQueue (\r
+  cFIFO        *Self,\r
+  FIFO_ElemBytes    As\r
+)\r
+{\r
+  size_t    Count;\r
+\r
+  if(Self->ReadIndex <= Self->WriteIndex) {\r
+    Count = Self->WriteIndex - Self->ReadIndex;\r
+  }\r
+  else {\r
+    Count = Self->NumElements - (Self->ReadIndex - Self->WriteIndex);\r
+  }\r
+  if(As == AsBytes) {\r
+    Count *= Self->ElementSize;\r
+  }\r
+  return Count;\r
+}\r
+\r
+/** Determine amount of free space in the FIFO that can be written into.\r
+\r
+    The number of items are either the number of bytes, or the number of elements\r
+    depending upon the value of the As enumerator.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+    @param[in]    As        An enumeration variable whose value determines whether the\r
+                            returned value is the number of bytes or the number of elements\r
+                            currently available in the FIFO.\r
+\r
+    @retval   0       The FIFO is full.\r
+    @retval   >=0     The number of items which can be accepted by the FIFO.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_FreeSpace (\r
+  cFIFO            *Self,\r
+  FIFO_ElemBytes    As\r
+)\r
+{\r
+  size_t    Count;\r
+  UINT32    RDex;\r
+  UINT32    WDex;\r
+\r
+  RDex = Self->ReadIndex;\r
+  WDex = Self->WriteIndex;\r
+\r
+  if(RDex <= WDex) {\r
+    Count = Self->NumElements - ((WDex - RDex) - 1);\r
+  }\r
+  else {\r
+    Count = (RDex - WDex);\r
+  }\r
+  if(As == AsBytes) {\r
+    Count *= Self->ElementSize;\r
+  }\r
+  return Count;\r
+}\r
+\r
+/** Reduce the FIFO contents by NumElem elements.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+    @param[in]    NumElem   Number of elements to delete from the FIFO.\r
+\r
+    @retval   0   FIFO is now empty.\r
+    @retval   N>0 There are still N elements in the FIFO.\r
+    @retval   -1  There are fewer than NumElem elements in the FIFO.\r
+**/\r
+static\r
+ssize_t\r
+FIFO_Reduce (\r
+  cFIFO    *Self,\r
+  size_t    NumElem\r
+  )\r
+{\r
+  size_t    QCount;\r
+  ssize_t   RetVal;\r
+\r
+  assert(Self != NULL);\r
+\r
+  QCount = FIFO_NumInQueue(Self, AsElements);\r
+  if(NumElem > QCount) {\r
+    RetVal = -1;\r
+    errno   = EINVAL;\r
+  }\r
+  else {\r
+    RetVal = (ssize_t)ModuloAdd(Self->ReadIndex, (UINT32)NumElem, Self->NumElements);\r
+    Self->ReadIndex = (UINT32)RetVal;\r
+\r
+    RetVal = (ssize_t)(QCount - NumElem);\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Test whether the FIFO is empty.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+\r
+    @retval   TRUE    The FIFO is empty.\r
+    @retval   FALSE   There is data in the FIFO.\r
+**/\r
+static\r
+BOOLEAN\r
+EFIAPI\r
+FIFO_IsEmpty (\r
+  cFIFO *Self\r
+  )\r
+{\r
+  assert(Self != NULL);\r
+\r
+  return (BOOLEAN)(Self->WriteIndex == Self->ReadIndex);\r
+}\r
+\r
+/** Test whether the FIFO is full.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+\r
+    @retval   TRUE    The FIFO is full.\r
+    @retval   FALSE   There is free space in the FIFO.\r
+**/\r
+static\r
+BOOLEAN\r
+EFIAPI\r
+FIFO_IsFull (\r
+  cFIFO *Self\r
+  )\r
+{\r
+  assert(Self != NULL);\r
+\r
+  return (BOOLEAN)(ModuloIncrement(Self->WriteIndex, Self->NumElements) == (INT32)Self->ReadIndex);\r
+}\r
+\r
+/** Add one or more elements to the FIFO.\r
+\r
+    This function allows one to add one or more elements, as specified by Count,\r
+    to the FIFO.  Each element is of the size specified when the FIFO object\r
+    was instantiated (FIFO.ElementSize).\r
+\r
+    pElement points to the first byte of the first element to be added.\r
+    If multiple elements are to be added, the elements are expected to be\r
+    organized as a packed array.\r
+\r
+    @param[in]    Self        Pointer to the FIFO instance.\r
+    @param[in]    pElement    Pointer to the element(s) to enqueue (add).\r
+    @param[in]    Count       Number of elements to add.\r
+\r
+    @retval   0       The FIFO is full.\r
+    @retval   >=0     The number of elements added to the FIFO.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_Enqueue (\r
+  cFIFO        *Self,\r
+  const void   *pElement,\r
+  size_t        Count\r
+  )\r
+{\r
+  uintptr_t     ElemPtr;\r
+  uintptr_t     QPtr;\r
+  size_t        i;\r
+  UINT32        SizeOfElement;\r
+  UINT32        Windex;\r
+\r
+  assert(Self != NULL);\r
+  assert(pElement != NULL);\r
+  assert(Count >= 0);\r
+\r
+  if(FIFO_IsFull(Self)) {\r
+    Count = 0;\r
+  }\r
+  else {\r
+    Count = MIN(Count, Self->FreeSpace(Self, AsElements));\r
+    SizeOfElement = Self->ElementSize;\r
+    Windex = Self->WriteIndex;\r
+\r
+    ElemPtr = (uintptr_t)pElement;\r
+\r
+    QPtr   = (uintptr_t)Self->Queue + (SizeOfElement * Windex);\r
+    for(i = 0; i < Count; ++i) {\r
+      (void)CopyMem((void *)QPtr, (const void *)ElemPtr, SizeOfElement);\r
+      Windex = (UINT32)ModuloIncrement(Windex, Self->NumElements);\r
+      if(Windex == 0) {   // If the index wrapped\r
+        QPtr = (uintptr_t)Self->Queue;\r
+      }\r
+      else {\r
+        QPtr += SizeOfElement;\r
+      }\r
+      ElemPtr += SizeOfElement;\r
+    }\r
+    (void)ZeroMem((void*)QPtr, SizeOfElement);\r
+    Self->WriteIndex = Windex;\r
+  }\r
+  return Count;\r
+}\r
+\r
+/** Read or copy elements from the FIFO.\r
+\r
+    This function allows one to read one or more elements, as specified by Count,\r
+    from the FIFO.  Each element is of the size specified when the FIFO object\r
+    was instantiated (FIFO.ElementSize).\r
+\r
+    pElement points to the destination of the first byte of the first element\r
+    to be read. If multiple elements are to be read, the elements are expected\r
+    to be organized as a packed array.\r
+\r
+    @param[in]    Self        Pointer to the FIFO instance.\r
+    @param[out]   pElement    Pointer to where to store the element(s) read from the FIFO.\r
+    @param[in]    Count       Number of elements to dequeue.\r
+    @param[in]    Consume     If TRUE, consume read elements.  Otherwise, preserve.\r
+\r
+    @retval   0       The FIFO is empty.\r
+    @retval   >=0     The number of elements read from the FIFO.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_Dequeue (\r
+  cFIFO    *Self,\r
+  void     *pElement,\r
+  size_t    Count,\r
+  BOOLEAN   Consume\r
+  )\r
+{\r
+  UINTN         ElemPtr;\r
+  UINTN         QPtr;\r
+  UINT32        RDex;\r
+  UINT32        SizeOfElement;\r
+  UINT32        i;\r
+\r
+  assert(Self != NULL);\r
+  assert(pElement != NULL);\r
+  assert(Count != 0);\r
+\r
+  if(FIFO_IsEmpty(Self)) {\r
+    Count = 0;\r
+  }\r
+  else {\r
+    RDex          = Self->ReadIndex;\r
+    SizeOfElement = Self->ElementSize;\r
+    ElemPtr       = (UINTN)pElement;\r
+    Count         = MIN(Count, Self->Count(Self, AsElements));\r
+\r
+    QPtr = (UINTN)Self->Queue + (RDex * Self->ElementSize);\r
+    for(i = 0; i < Count; ++i) {\r
+      (void)CopyMem((void *)ElemPtr, (const void *)QPtr, Self->ElementSize);\r
+      RDex = (UINT32)ModuloIncrement(RDex, Self->NumElements);\r
+      if(RDex == 0) {   // If the index wrapped\r
+        QPtr = (UINTN)Self->Queue;\r
+      }\r
+      else {\r
+        QPtr += Self->ElementSize;\r
+      }\r
+      ElemPtr += Self->ElementSize;\r
+    }\r
+    if(Consume) {\r
+      Self->ReadIndex = RDex;\r
+    }\r
+  }\r
+  return Count;\r
+}\r
+\r
+/** Read elements from the FIFO.\r
+\r
+    @param[in]    Self        Pointer to the FIFO instance.\r
+    @param[out]   pElement    Pointer to where to store the element read from the FIFO.\r
+    @param[in]    Count       Number of elements to dequeue.\r
+\r
+    @retval   0       The FIFO is empty.\r
+    @retval   >=0     The number of elements read from the FIFO.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_Read (\r
+  cFIFO    *Self,\r
+  void     *pElement,\r
+  size_t    Count\r
+  )\r
+{\r
+  return FIFO_Dequeue(Self, pElement, Count, TRUE);\r
+}\r
+\r
+/** Make a copy of the FIFO's data.\r
+    The contents of the FIFO is copied out and linearized without affecting the\r
+    FIFO contents.\r
+\r
+    @param[in]    Self        Pointer to the FIFO instance.\r
+    @param[out]   pElement    Pointer to where to store the elements copied from the FIFO.\r
+    @param[in]    Count       Number of elements to copy.\r
+\r
+    @retval   0       The FIFO is empty.\r
+    @retval   >=0     The number of elements copied from the FIFO.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_Copy (\r
+  cFIFO    *Self,\r
+  void     *pElement,\r
+  size_t    Count\r
+  )\r
+{\r
+  return FIFO_Dequeue(Self, pElement, Count, FALSE);\r
+}\r
+\r
+/** Get the FIFO's current Read Index.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+**/\r
+static\r
+UINT32\r
+EFIAPI\r
+FIFO_GetRDex (\r
+  cFIFO *Self\r
+)\r
+{\r
+  assert(Self != NULL);\r
+\r
+  return Self->ReadIndex;\r
+}\r
+\r
+/** Get the FIFO's current Write Index.\r
+\r
+    @param[in]    Self      Pointer to the FIFO instance.\r
+\r
+    @return   The current value of the FIFO's WriteIndex member is returned.\r
+**/\r
+static\r
+UINT32\r
+EFIAPI\r
+FIFO_GetWDex (\r
+  cFIFO *Self\r
+)\r
+{\r
+  assert(Self != NULL);\r
+\r
+  return Self->WriteIndex;\r
+}\r
+\r
+/** Cleanly delete a FIFO instance.\r
+\r
+    @param[in]    Self              Pointer to the FIFO instance.\r
+**/\r
+static\r
+void\r
+EFIAPI\r
+FIFO_Delete (\r
+  cFIFO *Self\r
+  )\r
+{\r
+  assert(Self != NULL);\r
+\r
+  if(Self->Queue != NULL) {\r
+    FreePool(Self->Queue);\r
+    Self->Queue = NULL;     // Zombie catcher\r
+  }\r
+  FreePool(Self);\r
+}\r
+\r
+/** Empty the FIFO, discarding up to NumToFlush elements.\r
+\r
+    @param[in]    Self              Pointer to the FIFO instance.\r
+    @param[in]    NumToFlush        Number of elements to flush from the FIFO.\r
+                                    If larger than the number of elements in the\r
+                                    FIFO, the FIFO is emptied.\r
+\r
+    @return     Returns the number of elements remaining in the FIFO after the flush.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_Flush (\r
+  cFIFO  *Self,\r
+  size_t  NumToFlush\r
+  )\r
+{\r
+  size_t  NumInQ;\r
+  size_t  Remainder;\r
+\r
+  assert(Self != NULL);\r
+\r
+  NumInQ = FIFO_FreeSpace(Self, AsElements);\r
+  if(NumToFlush >= NumInQ) {\r
+    Self->ReadIndex   = 0;\r
+    Self->WriteIndex  = 0;\r
+    Remainder = 0;\r
+  }\r
+  else {\r
+    Remainder = FIFO_Reduce(Self, NumToFlush);\r
+  }\r
+  return Remainder;\r
+}\r
+\r
+/** Remove the most recently added element from the FIFO.\r
+\r
+    @param[in]    Self              Pointer to the FIFO instance.\r
+\r
+    @return     Returns the number of elements remaining in the FIFO.\r
+**/\r
+static\r
+size_t\r
+EFIAPI\r
+FIFO_Truncate (\r
+  cFIFO  *Self\r
+  )\r
+{\r
+  size_t  Remainder;\r
+\r
+  assert(Self != NULL);\r
+\r
+  Remainder = Self->Count(Self, AsElements);\r
+  if(Remainder > 0) {\r
+    Self->WriteIndex = (UINT32)ModuloDecrement(Self->WriteIndex, Self->NumElements);\r
+    --Remainder;\r
+  }\r
+  return Remainder;\r
+}\r
+\r
+/** Construct a new instance of a FIFO Queue.\r
+\r
+    @param[in]    NumElements   Number of elements to be contained in the new FIFO.\r
+    @param[in]    ElementSize   Size, in bytes, of an element.\r
+\r
+    @retval   NULL      Unable to create the instance.\r
+    @retval   NonNULL   Pointer to the new FIFO instance.\r
+**/\r
+cFIFO *\r
+EFIAPI\r
+New_cFIFO(\r
+  UINT32    NumElements,\r
+  size_t    ElementSize\r
+  )\r
+{\r
+  cFIFO        *FIFO;\r
+  UINT8        *Queue;\r
+\r
+  FIFO = NULL;\r
+  if((NumElements > 2) && (ElementSize > 0)) {\r
+    FIFO = (cFIFO *)AllocatePool(sizeof(cFIFO));\r
+    if(FIFO != NULL) {\r
+      Queue = (UINT8 *)AllocateZeroPool(NumElements * ElementSize);\r
+      if(Queue != NULL) {\r
+        FIFO->Write       = FIFO_Enqueue;\r
+        FIFO->Read        = FIFO_Read;\r
+        FIFO->Copy        = FIFO_Copy;\r
+        FIFO->IsEmpty     = FIFO_IsEmpty;\r
+        FIFO->IsFull      = FIFO_IsFull;\r
+        FIFO->Count       = FIFO_NumInQueue;\r
+        FIFO->FreeSpace   = FIFO_FreeSpace;\r
+        FIFO->Flush       = FIFO_Flush;\r
+        FIFO->Truncate    = FIFO_Truncate;\r
+        FIFO->Delete      = FIFO_Delete;\r
+        FIFO->GetRDex     = FIFO_GetRDex;\r
+        FIFO->GetWDex     = FIFO_GetWDex;\r
+\r
+        FIFO->Queue       = Queue;\r
+        FIFO->ElementSize = (UINT32)ElementSize;\r
+        FIFO->NumElements = (UINT32)NumElements;\r
+        FIFO->ReadIndex   = 0;\r
+        FIFO->WriteIndex  = 0;\r
+      }\r
+      else {\r
+        FreePool(FIFO);\r
+        FIFO = NULL;\r
+      }\r
+    }\r
+  }\r
+  return FIFO;\r
+}\r
index 5736428db5bf2bc07d50f63ba3086f77b2bea0e1..0c84c160e0b8afbf0f4a9df18a23a04c3a69d702 100644 (file)
@@ -158,9 +158,9 @@ ShellAppMain (
       mfd[i].MyFD = (UINT16)i;\r
     }\r
 \r
-    i = open("stdin:", O_RDONLY, 0444);\r
+    i = open("stdin:", (O_RDONLY | O_TTY_INIT), 0444);\r
     if(i == 0) {\r
-      i = open("stdout:", O_WRONLY, 0222);\r
+      i = open("stdout:", (O_WRONLY | O_TTY_INIT), 0222);\r
       if(i == 1) {\r
         i = open("stderr:", O_WRONLY, 0222);\r
       }\r
index 4897a2e56e639476a7c041d5b686f6bdce2c4f24..927ec944eaeafa5d444322d5bc3cd72c82089209 100644 (file)
@@ -3,6 +3,13 @@
 \r
   Manipulates abstractions for stdin, stdout, stderr.\r
 \r
+  This device is a WIDE device and this driver returns WIDE\r
+  characters.  It this the responsibility of the caller to convert between\r
+  narrow and wide characters in order to perform the desired operations.\r
+\r
+  The devices status as a wide device is indicatd by _S_IWTTY being set in\r
+  f_iflags.\r
+\r
   Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials are licensed and made available under\r
   the terms and conditions of the BSD License that accompanies this distribution.\r
@@ -30,6 +37,7 @@
 #include  <unistd.h>\r
 #include  <kfile.h>\r
 #include  <Device/Device.h>\r
+#include  <Device/IIO.h>\r
 #include  <MainData.h>\r
 \r
 static const CHAR16* const\r
@@ -46,7 +54,7 @@ static const int stdioFlags[NUM_SPECIAL] = {
 static DeviceNode    *ConNode[NUM_SPECIAL];\r
 static ConInstance   *ConInstanceList;\r
 \r
-static wchar_t       *ConReadBuf;\r
+static cIIO          *IIO;\r
 \r
 /* Flags settable by Ioctl */\r
 static BOOLEAN        TtyCooked;\r
@@ -58,10 +66,10 @@ static BOOLEAN        TtyEcho;
     large enough to hold the converted results.  It is guaranteed\r
     that there will be fewer than n characters placed in dest.\r
 \r
-    @param  dest    WCS buffer to receive the converted string.\r
-    @param  buf     MBCS string to convert to WCS.\r
-    @param  n       Number of BYTES contained in buf.\r
-    @param  Cs      Pointer to the character state object for this stream\r
+    @param[out]     dest    WCS buffer to receive the converted string.\r
+    @param[in]      buf     MBCS string to convert to WCS.\r
+    @param[in]      n       Number of BYTES contained in buf.\r
+    @param[in,out]  Cs      Pointer to the character state object for this stream\r
 \r
     @return   The number of BYTES consumed from buf.\r
 **/\r
@@ -94,6 +102,13 @@ WideTtyCvt( CHAR16 *dest, const char *buf, ssize_t n, mbstate_t *Cs)
   return i;\r
 }\r
 \r
+/** Close an open file.\r
+\r
+    @param[in]  filp    Pointer to the file descriptor structure for this file.\r
+\r
+    @retval   0     The file has been successfully closed.\r
+    @retval   -1    filp does not point to a valid console descriptor.\r
+**/\r
 static\r
 int\r
 EFIAPI\r
@@ -106,13 +121,25 @@ da_ConClose(
   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
   // Quick check to see if Stream looks reasonable\r
   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'\r
+    errno     = EINVAL;\r
     EFIerrno = RETURN_INVALID_PARAMETER;\r
     return -1;    // Looks like a bad File Descriptor pointer\r
   }\r
   gMD->StdIo[Stream->InstanceNum] = NULL;   // Mark the stream as closed\r
-  return RETURN_SUCCESS;\r
+  return 0;\r
 }\r
 \r
+/** Position the console cursor to the coordinates specified by Position.\r
+\r
+    @param[in]  filp      Pointer to the file descriptor structure for this file.\r
+    @param[in]  Position  A value containing the target X and Y coordinates.\r
+    @param[in]  whence    Ignored by the Console device.\r
+\r
+    @retval   Position    Success.  Returns a copy of the Position argument.\r
+    @retval   -1          filp is not associated with a valid console stream.\r
+    @retval   -1          This console stream is attached to stdin.\r
+    @retval   -1          The SetCursorPosition operation failed.\r
+**/\r
 static\r
 off_t\r
 EFIAPI\r
@@ -155,11 +182,14 @@ da_ConSeek(
 \r
 /* Write a NULL terminated WCS to the EFI console.\r
 \r
-  @param[in,out]  BufferSize  Number of bytes in Buffer.  Set to zero if\r
-                              the string couldn't be displayed.\r
+  NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters received\r
+        by da_ConWrite are WIDE characters.  It is the responsibility of the\r
+        higher-level function(s) to perform any necessary conversions.\r
+\r
+    @param[in,out]  BufferSize  Number of characters in Buffer.\r
   @param[in]      Buffer      The WCS string to be displayed\r
 \r
-  @return   The number of BYTES written.  Because of MBCS, this may be more than number of characters.\r
+    @return   The number of Characters written.\r
 */\r
 static\r
 ssize_t\r
@@ -174,8 +204,10 @@ da_ConWrite(
   EFI_STATUS                          Status;\r
   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;\r
   ConInstance                        *Stream;\r
-  ssize_t                             NumBytes;\r
+  ssize_t                             NumChar;\r
+  XY_OFFSET                          CursorPos;\r
 \r
+  NumChar = -1;\r
   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
   // Quick check to see if Stream looks reasonable\r
   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'\r
@@ -190,35 +222,45 @@ da_ConWrite(
   // Everything is OK to do the write.\r
   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
 \r
-  // Convert string from MBCS to WCS and translate \n to \r\n.\r
-  NumBytes = WideTtyCvt(gMD->UString, (const char *)Buffer, (ssize_t)BufferSize, &Stream->CharState);\r
-  BufferSize = NumBytes;\r
+  Status = EFI_SUCCESS;\r
+  if(Position != NULL) {\r
+    CursorPos.Offset = *Position;\r
 \r
+    Status = Proto->SetCursorPosition(Proto,\r
+                                      (INTN)CursorPos.XYpos.Column,\r
+                                      (INTN)CursorPos.XYpos.Row);\r
 \r
+  }\r
+  if(!RETURN_ERROR(Status)) {\r
   // Send the Unicode buffer to the console\r
-  Status = Proto->OutputString( Proto, gMD->UString);\r
-  // Depending on status, update BufferSize and return\r
-  if(RETURN_ERROR(Status)) {\r
-    BufferSize = 0;     // We don't really know how many characters made it out\r
+    Status = Proto->OutputString( Proto, (CHAR16 *)Buffer);\r
   }\r
-  else {\r
-    //BufferSize = NumBytes;\r
-    Stream->NumWritten += NumBytes;\r
+\r
+  // Depending on status, update BufferSize and return\r
+  if(!RETURN_ERROR(Status)) {\r
+    //BufferSize = NumChar;\r
+    NumChar = BufferSize;\r
+    Stream->NumWritten += NumChar;\r
   }\r
   EFIerrno = Status;      // Make error reason available to caller\r
-  return BufferSize;\r
+  return NumChar;\r
 }\r
 \r
-/** Read characters from the console input device.\r
+/** Read a wide character from the console input device.\r
+\r
+  NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters returned\r
+        by da_ConRead are WIDE characters.  It is the responsibility of the\r
+        higher-level function(s) to perform any necessary conversions.\r
 \r
-    @param[in,out]  filp          Pointer to file descriptor for this file.\r
-    @param[in,out]  offset        Ignored.\r
+    @param[in,out]  BufferSize  Number of characters in Buffer.\r
+    @param[in]      filp          Pointer to file descriptor for this file.\r
+    @param[in]      offset        Ignored.\r
     @param[in]      BufferSize    Buffer size, in bytes.\r
     @param[out]     Buffer        Buffer in which to place the read characters.\r
 \r
-    @return     Number of bytes actually placed into Buffer.\r
-\r
-    @todo       Handle encodings other than ASCII-7 and UEFI.\r
+    @retval    -1   An error has occurred.  Reason in errno and EFIerrno.\r
+    @retval    -1   No data is available.  errno is set to EAGAIN\r
+    @retval     1   One wide character has been placed in Buffer\r
 **/\r
 static\r
 ssize_t\r
@@ -232,84 +274,80 @@ da_ConRead(
 {\r
   EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *Proto;\r
   ConInstance                      *Stream;\r
-  wchar_t                          *OutPtr;\r
-  EFI_INPUT_KEY                     Key;\r
-  UINTN                             NumChar;\r
-  UINTN                             Edex;\r
+  cIIO                              *Self;\r
+  EFI_INPUT_KEY                     Key = {0,0};\r
   EFI_STATUS                        Status = RETURN_SUCCESS;\r
-  UINTN                             i;\r
-  char                              EchoBuff[MB_CUR_MAX + 1];\r
-  int                               NumEcho;\r
+  UINTN                             Edex;\r
+  ssize_t                           NumRead;\r
+  int                               Flags;\r
+  wchar_t                           RetChar;   // Default to No Data\r
 \r
-  Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
-  // Quick check to see if Stream looks reasonable\r
-  if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'\r
-    EFIerrno = RETURN_INVALID_PARAMETER;\r
-    return -1;    // Looks like a bad This pointer\r
-  }\r
-  if(Stream->InstanceNum != STDIN_FILENO) {\r
-    // Read only valid for stdin\r
-    EFIerrno = RETURN_UNSUPPORTED;\r
-    return -1;\r
+  NumRead = -1;\r
+  if(BufferSize < sizeof(wchar_t)) {\r
+    errno = EINVAL;     // Buffer is too small to hold one character\r
   }\r
-  // It looks like things are OK for trying to read\r
-  // We will accumulate *BufferSize characters or until we encounter\r
-  // an "activation" character.  Currently any control character.\r
+  else {\r
+    Self = (cIIO *)filp->devdata;\r
+  Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
   Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
-  OutPtr = ConReadBuf;\r
-  NumChar = (BufferSize > MAX_INPUT)? MAX_INPUT : BufferSize;\r
-  i = 0;\r
-  do {\r
+    Flags = filp->Oflags;\r
     if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
+      // No data pending in the Un-get buffer.  Get a char from the hardware.\r
+      if((Flags & O_NONBLOCK) == 0) {\r
+        // Read a byte in Blocking mode\r
       Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
-      if(Status != RETURN_SUCCESS) {\r
-        break;\r
+        EFIerrno = Status;\r
+        if(Status != EFI_SUCCESS) {\r
+          errno = EINVAL;\r
       }\r
+        else {\r
       Status = Proto->ReadKeyStroke(Proto, &Key);\r
-      if(Status != RETURN_SUCCESS) {\r
-        break;\r
+          if(Status == EFI_SUCCESS) {\r
+            NumRead = 1;   // Indicate that Key holds the data\r
+          }\r
+          else {\r
+            errno = EIO;\r
+          }\r
+        }\r
+      }\r
+      else {\r
+        // Read a byte in Non-Blocking mode\r
+      Status = Proto->ReadKeyStroke(Proto, &Key);\r
+        EFIerrno = Status;\r
+        if(Status == EFI_SUCCESS) {\r
+          // Got a keystroke.\r
+          NumRead = 1;   // Indicate that Key holds the data\r
+        }\r
+        else if(Status == EFI_NOT_READY) {\r
+          // Keystroke data is not available\r
+          errno = EAGAIN;\r
+        }\r
+        else {\r
+          // Hardware error\r
+          errno = EIO;\r
+        }\r
       }\r
     }\r
     else {\r
+      // Use the data in the Un-get buffer\r
       Key.ScanCode          = Stream->UnGetKey.ScanCode;\r
       Key.UnicodeChar       = Stream->UnGetKey.UnicodeChar;\r
       Stream->UnGetKey.ScanCode     = SCAN_NULL;\r
       Stream->UnGetKey.UnicodeChar  = CHAR_NULL;\r
+      NumRead = 1;   // Indicate that Key holds the data\r
     }\r
-    if(Key.ScanCode == SCAN_NULL) {\r
-      NumEcho = 0;\r
-      if(TtyCooked && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {\r
-        *OutPtr++ = CHAR_LINEFEED;\r
-        NumEcho = wctomb(EchoBuff, CHAR_LINEFEED);\r
-      }\r
-      else {\r
-        *OutPtr++ = Key.UnicodeChar;\r
-        NumEcho = wctomb(EchoBuff, Key.UnicodeChar);\r
+    // If we have data, prepare it for return.\r
+    if(NumRead == 1) {\r
+      RetChar = Key.UnicodeChar;\r
+      if((RetChar == 0) && ((Self->Termio.c_iflag & IGNSPEC) == 0)) {\r
+        // Must be a control, function, or other non-printable key.\r
+        // Map it into the Platform portion of the Unicode private use area\r
+        RetChar = (Key.ScanCode == 0) ? 0 : 0xF900U - Key.ScanCode;\r
       }\r
-      ++i;\r
-      EchoBuff[NumEcho] = 0;  /* Terminate the Echo buffer */\r
-      if(TtyEcho) {\r
-        /* Echo the character just input */\r
-        da_ConWrite(&gMD->fdarray[STDOUT_FILENO], NULL, 2, EchoBuff);\r
+      *((wchar_t *)Buffer) = RetChar;\r
       }\r
     }\r
-    if(iswcntrl(Key.UnicodeChar)) {    // If a control character, or a scan code\r
-      break;\r
-    }\r
-  } while(i < NumChar);\r
-\r
-  *OutPtr = L'\0';    // Terminate the input buffer\r
-\r
-  /*  Convert the input buffer and place in Buffer.\r
-      If the fully converted input buffer won't fit, write what will and\r
-      leave the rest in ConReadBuf with ConReadLeft indicating how many\r
-      unconverted characters remain in ConReadBuf.\r
-  */\r
-  NumEcho = (int)wcstombs(Buffer, ConReadBuf, BufferSize);   /* Re-use NumEcho to hold number of bytes in Buffer */\r
-  /* More work needs to be done before locales other than C can be supported. */\r
-\r
-  EFIerrno = Status;\r
-  return (ssize_t)NumEcho;  // Will be 0 if we didn't get a key\r
+  return NumRead;\r
 }\r
 \r
 /** Console-specific helper function for the fstat() function.\r
@@ -320,6 +358,14 @@ da_ConRead(
     st_blksize    Set to 1 since this is a character device\r
 \r
     All other members of the stat structure are left unchanged.\r
+\r
+    @param[in]      filp          Pointer to file descriptor for this file.\r
+    @param[out]     Buffer        Pointer to a stat structure to receive the information.\r
+    @param[in,out]  Something     Ignored.\r
+\r
+    @retval   0   Successful completion.\r
+    @retval   -1  Either filp is not associated with a console stream, or\r
+                  Buffer is NULL.  errno is set to EINVAL.\r
 **/\r
 static\r
 int\r
@@ -343,6 +389,7 @@ da_ConStat(
   if ((Stream->Cookie != CON_COOKIE) ||    // Cookie == 'IoAb'\r
       (Buffer == NULL))\r
   {\r
+    errno     = EINVAL;\r
     EFIerrno = RETURN_INVALID_PARAMETER;\r
     return -1;\r
   }\r
@@ -378,6 +425,14 @@ da_ConStat(
   return 0;\r
 }\r
 \r
+/** Console-specific helper for the ioctl system call.\r
+\r
+    The console device does not directly participate in ioctl operations.\r
+    This function completes the device abstraction and returns an error value\r
+    to indicate that the function is not supported for this device.\r
+\r
+    @retval   -1    Function is not supported for this device.\r
+**/\r
 static\r
 int\r
 EFIAPI\r
@@ -387,10 +442,21 @@ da_ConIoctl(
   va_list             argp\r
   )\r
 {\r
-  return -EPERM;\r
+  errno   = ENODEV;\r
+  return  -1;\r
 }\r
 \r
 /** Open an abstract Console Device.\r
+\r
+    @param[in]    DevNode       Pointer to the Device control structure for this stream.\r
+    @param[in]    filp          Pointer to the new file control structure for this stream.\r
+    @param[in]    DevInstance   Not used for the console device.\r
+    @param[in]    Path          Not used for the console device.\r
+    @param[in]    MPath         Not used for the console device.\r
+\r
+    @retval   0   This console stream has been successfully opened.\r
+    @retval   -1  The DevNode or filp pointer is NULL.\r
+    @retval   -1  DevNode does not point to a valid console stream device.\r
 **/\r
 int\r
 EFIAPI\r
@@ -403,36 +469,57 @@ da_ConOpen(
   )\r
 {\r
   ConInstance                      *Stream;\r
+  UINT32          Instance;\r
+  int             RetVal = -1;\r
 \r
-  if((filp == NULL)           ||\r
-     (DevNode  == NULL))\r
+  if((filp    != NULL)    &&\r
+      (DevNode != NULL))\r
   {\r
-    EFIerrno = RETURN_INVALID_PARAMETER;\r
-    errno = EINVAL;\r
-    return -1;\r
-  }\r
   Stream = (ConInstance *)DevNode->InstanceList;\r
   // Quick check to see if Stream looks reasonable\r
-  if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'\r
+    if(Stream->Cookie == CON_COOKIE)\r
+    {\r
+      Instance = Stream->InstanceNum;\r
+      if(Instance < NUM_SPECIAL) {\r
+        gMD->StdIo[Instance] = Stream;\r
+        filp->f_iflags |= (_S_IFCHR | _S_ITTY | _S_IWTTY | _S_ICONSOLE);\r
+        filp->f_offset = 0;\r
+        filp->f_ops = &Stream->Abstraction;\r
+        filp->devdata = (void *)IIO;\r
+        RetVal = 0;\r
+      }\r
+    }\r
+  }\r
+  if (RetVal < 0) {\r
     EFIerrno = RETURN_INVALID_PARAMETER;\r
     errno = EINVAL;\r
-    return -1;    // Looks like a bad This pointer\r
   }\r
-  gMD->StdIo[Stream->InstanceNum] = Stream;\r
-  filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE);\r
-  filp->f_offset = 0;\r
-  filp->f_ops = &Stream->Abstraction;\r
+  return RetVal;\r
 \r
-  return 0;\r
 }\r
 \r
 #include  <sys/poll.h>\r
 /*  Returns a bit mask describing which operations could be completed immediately.\r
 \r
+    Testable Events for this device are:\r
     (POLLIN | POLLRDNORM)   A Unicode character is available to read\r
     (POLLIN)                A ScanCode is ready.\r
     (POLLOUT)               The device is ready for output - always set on stdout and stderr.\r
 \r
+    Non-testable Events which are only valid in return values are:\r
+      POLLERR                 The specified device is not one of stdin, stdout, or stderr.\r
+      POLLHUP                 The specified stream has been disconnected\r
+      POLLNVAL                da_ConPoll was called with an invalid parameter.\r
+\r
+  NOTE: The "Events" handled by this function are not UEFI events.\r
+\r
+    @param[in]  filp      Pointer to the file control structure for this stream.\r
+    @param[in]  events    A bit mask identifying the events to be examined\r
+                          for this device.\r
+\r
+    @return   Returns a bit mask comprised of both testable and non-testable\r
+              event codes indicating both the state of the operation and the\r
+              status of the device.\r
 */\r
 static\r
 short\r
@@ -450,6 +537,7 @@ da_ConPoll(
   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
   // Quick check to see if Stream looks reasonable\r
   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'\r
+    errno     = EINVAL;\r
     EFIerrno = RETURN_INVALID_PARAMETER;\r
     return POLLNVAL;    // Looks like a bad filp pointer\r
   }\r
@@ -495,15 +583,18 @@ __Cons_construct(
 )\r
 {\r
   ConInstance    *Stream;\r
-  RETURN_STATUS   Status = RETURN_SUCCESS;\r
+  RETURN_STATUS   Status;\r
   int             i;\r
 \r
+  Status = RETURN_OUT_OF_RESOURCES;\r
   ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));\r
-  ConReadBuf      = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));\r
-  if((ConInstanceList == NULL) || (ConReadBuf == NULL))  {\r
-    return RETURN_OUT_OF_RESOURCES;\r
+  if(ConInstanceList != NULL) {\r
+    IIO = New_cIIO();\r
+    if(IIO == NULL) {\r
+      FreePool(ConInstanceList);\r
   }\r
-\r
+    else {\r
+      Status = RETURN_SUCCESS;\r
   for( i = 0; i < NUM_SPECIAL; ++i) {\r
     // Get pointer to instance.\r
     Stream = &ConInstanceList[i];\r
@@ -553,9 +644,10 @@ __Cons_construct(
     if(Stream->Dev == NULL) {\r
       continue;                 // No device for this stream.\r
     }\r
-    ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]);\r
+        ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream,\r
+                                   1, sizeof(ConInstance), stdioFlags[i]);\r
     if(ConNode[i] == NULL) {\r
-      Status = EFIerrno;\r
+          Status = EFIerrno;    // Grab error code that DevRegister produced.\r
       break;\r
     }\r
     Stream->Parent = ConNode[i];\r
@@ -563,7 +655,8 @@ __Cons_construct(
   /* Initialize Ioctl flags until Ioctl is really implemented. */\r
   TtyCooked = TRUE;\r
   TtyEcho   = TRUE;\r
-\r
+    }\r
+  }\r
   return  Status;\r
 }\r
 \r
@@ -584,15 +677,16 @@ __Cons_deconstruct(
   if(ConInstanceList != NULL) {\r
     FreePool(ConInstanceList);\r
   }\r
-  if(ConReadBuf != NULL) {\r
-    FreePool(ConReadBuf);\r
+  if(IIO != NULL) {\r
+    IIO->Delete(IIO);\r
+    IIO = NULL;\r
   }\r
 \r
   return RETURN_SUCCESS;\r
 }\r
 \r
 /* ######################################################################### */\r
-#if 0 /* Not implemented for Console */\r
+#if 0 /* Not implemented (yet?) for Console */\r
 \r
 static\r
 int\r
index f6d375e6db603eb7f6d03874cf882aa9a217388a..8d95fbad5eb3a06b0fbc1309d1715a576c60e048 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
     Device Abstraction: device creation utility functions.\r
 \r
-    Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+    Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>\r
     This program and the accompanying materials are licensed and made available under\r
     the terms and conditions of the BSD License that accompanies this distribution.\r
     The full text of the license may be found at\r
@@ -44,22 +44,40 @@ int     EFIAPI fnullop_flush (struct __filedes *filp)
 { return 0; }\r
 \r
 int     EFIAPI fbadop_stat   (struct __filedes *filp, struct stat *StatBuf, void *Buf)\r
-{ return -EPERM;  }\r
+{\r
+  errno = EPERM;\r
+  return -1;\r
+}\r
 \r
 int     EFIAPI fbadop_ioctl  (struct __filedes *filp, ULONGN Cmd, va_list argp)\r
-{ return -EPERM;  }\r
+{\r
+  errno = EPERM;\r
+  return -1;\r
+}\r
 \r
 int     EFIAPI fbadop_delete (struct __filedes *filp)\r
-{ return -EPERM;  }\r
+{\r
+  errno = EPERM;\r
+  return -1;\r
+}\r
 \r
 int     EFIAPI fbadop_mkdir  (const char *path, __mode_t perms)\r
-{ return -EPERM;  }\r
+{\r
+  errno = EPERM;\r
+  return -1;\r
+}\r
 \r
 int     EFIAPI fbadop_rename   (const char *from, const char *to)\r
-{ return -EPERM;  }\r
+{\r
+  errno = EPERM;\r
+  return -1;\r
+}\r
 \r
 int     EFIAPI fbadop_rmdir    (struct __filedes *filp)\r
-{ return -EPERM;  }\r
+{\r
+  errno = EPERM;\r
+  return -1;\r
+}\r
 \r
 /** Add a new device to the device list.\r
     If both DevName and DevProto are NULL, register this as the Default device.\r
index 802c6eb13cd25c2351db2c4e0d61f56a1399f6ca..e23193f4e2d05747c6cd26fd9a4da6fba935934d 100644 (file)
@@ -1,7 +1,7 @@
 ## @file\r
 #  Standard C library: Console Device Abstraction.\r
 #\r
-#  Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>\r
 #  This program and the accompanying materials are licensed and made available\r
 #  under the terms and conditions of the BSD License which accompanies this\r
 #  distribution.  The full text of the license may be found at\r
@@ -44,8 +44,9 @@
   LibC\r
   LibWchar\r
   LibUefi\r
+  LibIIO\r
   DevUtility\r
 \r
 [Protocols]\r
-  gEfiSimpleTextInProtocolGuid\r
-  gEfiSimpleTextOutProtocolGuid\r
+  gEfiSimpleTextInProtocolGuid        ## CONSUMED\r
+  gEfiSimpleTextOutProtocolGuid       ## CONSUMED\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/CanonRead.c b/StdLib/LibC/Uefi/InteractiveIO/CanonRead.c
new file mode 100644 (file)
index 0000000..db6af6e
--- /dev/null
@@ -0,0 +1,161 @@
+/** @file\r
+  Canonical Interactive Input Function.\r
+\r
+  The functions assume that isatty() is TRUE at the time they are called.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <errno.h>\r
+#include  <sys/syslimits.h>\r
+#include  <sys/termios.h>\r
+#include  <Device/IIO.h>\r
+#include  <MainData.h>\r
+#include  "IIOutilities.h"\r
+#include  "IIOechoCtrl.h"\r
+\r
+/** Read a line from the input file in canonical mode.\r
+    Perform echoing and input processing as directed by the termios flags.\r
+\r
+    @param[in]    filp      A pointer to a file descriptor structure.\r
+\r
+    @return     The number of characters in the input buffer, or -1 if there\r
+                was an error.\r
+**/\r
+ssize_t\r
+IIO_CanonRead (\r
+  struct __filedes *filp\r
+  )\r
+{\r
+  cIIO             *This;\r
+  cFIFO            *InBuf;\r
+  struct termios   *Termio;\r
+  struct __filedes *fpOut;\r
+  size_t            NumRead;\r
+  wint_t            InChar;\r
+  tcflag_t          IFlag;\r
+  tcflag_t          LFlag;\r
+  BOOLEAN           EchoIsOK;\r
+  BOOLEAN           Activate;\r
+  BOOLEAN           FirstRead;\r
+  int               OutMode;\r
+  UINTN             MaxColumn;\r
+  UINTN             MaxRow;\r
+\r
+  NumRead   = MAX_INPUT;    // Workaround "potentially uninitialized" warning\r
+  EchoIsOK  = FALSE;\r
+  FirstRead = TRUE;\r
+  This      = filp->devdata;\r
+  Termio    = &This->Termio;\r
+  InBuf     = This->InBuf;\r
+\r
+  // Get a copy of the flags we are going to use\r
+  IFlag = Termio->c_iflag;\r
+  LFlag = Termio->c_lflag;\r
+\r
+  /* Determine what the current screen size is. Also validates the output device. */\r
+  OutMode = IIO_GetOutputSize(STDOUT_FILENO, &MaxColumn, &MaxRow);\r
+  if(OutMode >= 0) {\r
+    /*  Set the maximum screen dimensions. */\r
+    This->MaxColumn = MaxColumn;\r
+    This->MaxRow    = MaxRow;\r
+\r
+    /*  Record where the cursor is at the beginning of this Input operation.\r
+        The currently set stdout device is used to determine this.  If there is\r
+        no stdout, or stdout is not an interactive device, nothing is recorded.\r
+    */\r
+    if (IIO_GetCursorPosition(STDOUT_FILENO, &This->InitialXY.Column, &This->InitialXY.Row) >= 0) {\r
+      This->CurrentXY.Column  = This->InitialXY.Column;\r
+      This->CurrentXY.Row     = This->InitialXY.Row;\r
+      EchoIsOK  = TRUE;   // Can only echo to stdout\r
+    }\r
+  }\r
+\r
+  // For now, we only echo to stdout.\r
+  fpOut = &gMD->fdarray[STDOUT_FILENO];\r
+\r
+  //  Input and process characters until BufferSize is exhausted.\r
+  do {\r
+    InChar = IIO_GetInChar(filp, FirstRead);\r
+    FirstRead = FALSE;\r
+    Activate  = TRUE;\r
+    if(InChar == CHAR_CARRIAGE_RETURN) {\r
+      if((IFlag & IGNCR) != 0) {\r
+        continue;   // Restart the do loop, discarding the CR\r
+      }\r
+      else if((IFlag & ICRNL) != 0) {\r
+        InChar = L'\n';\r
+      }\r
+    }\r
+    else if(InChar == CHAR_LINEFEED) {\r
+      if((IFlag & INLCR) != 0) {\r
+        InChar = L'\r';\r
+      }\r
+    }\r
+    else if(CCEQ(Termio->c_cc[VINTR], InChar)) {\r
+      if((LFlag & ISIG) != 0) {\r
+        // Raise Signal\r
+        // Flush Input Buffer\r
+        // Return to caller\r
+        InChar = IIO_ECHO_DISCARD;\r
+        errno = EINTR;\r
+      }\r
+      else {\r
+        Activate = FALSE;\r
+      }\r
+    }\r
+    else if(CCEQ(Termio->c_cc[VQUIT], InChar)) {\r
+      if((LFlag & ISIG) != 0) {\r
+        // Raise Signal\r
+        // Flush Input Buffer\r
+        // Return to caller\r
+        InChar = IIO_ECHO_DISCARD;\r
+        errno = EINTR;\r
+      }\r
+      else {\r
+        Activate = FALSE;\r
+      }\r
+    }\r
+    else if(CCEQ(Termio->c_cc[VEOF], InChar)) {\r
+      InChar = WEOF;\r
+    }\r
+    else if(CCEQ(Termio->c_cc[VEOL], InChar)) {\r
+      EchoIsOK = FALSE;   // Buffer, but don't echo this character\r
+    }\r
+    else if(CCEQ(Termio->c_cc[VERASE], InChar)) {\r
+      InChar = IIO_ECHO_ERASE;\r
+      Activate = FALSE;\r
+    }\r
+    else if(CCEQ(Termio->c_cc[VKILL], InChar)) {\r
+      InChar = IIO_ECHO_KILL;\r
+      Activate = FALSE;\r
+    }\r
+    else {\r
+      if((InChar < TtySpecKeyMin) || (InChar >= TtyFunKeyMax)) {\r
+        Activate = FALSE;\r
+      }\r
+    }\r
+    /** The Echo function is responsible for:\r
+          * Adding the character to the input buffer, if appropriate.\r
+          * Removing characters from the input buffer for ERASE and KILL processing.\r
+          * Visually removing characters from the screen if ECHOE is set.\r
+          * Ensuring one can not backspace beyond the beginning of the input text.\r
+          * Sending final echo strings to output.\r
+    **/\r
+    (void)This->Echo(fpOut, (wchar_t)InChar, EchoIsOK);\r
+    NumRead = InBuf->Count(InBuf, AsElements);\r
+  } while((NumRead < MAX_INPUT) &&\r
+          (Activate == FALSE));\r
+\r
+  return (ssize_t)NumRead;\r
+}\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIO.c b/StdLib/LibC/Uefi/InteractiveIO/IIO.c
new file mode 100644 (file)
index 0000000..65b61d9
--- /dev/null
@@ -0,0 +1,373 @@
+/** @file\r
+  Definitions for the Interactive IO library.\r
+\r
+  The functions assume that isatty() is TRUE at the time they are called.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+#include  <Library/MemoryAllocationLib.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <assert.h>\r
+#include  <errno.h>\r
+#include  <sys/syslimits.h>\r
+#include  <sys/termios.h>\r
+#include  <Device/IIO.h>\r
+#include  <MainData.h>\r
+#include  "IIOutilities.h"\r
+#include  "IIOechoCtrl.h"\r
+\r
+/** Read from an Interactive IO device.\r
+\r
+  NOTE: If _S_IWTTY is set, the internal buffer contains WIDE characters.\r
+        They will need to be converted to MBCS when returned.\r
+\r
+    Input is line buffered if ICANON is set,\r
+    otherwise MIN determines how many characters to input.\r
+    Currently MIN is always zero, meaning 0 or 1 character is input in\r
+    noncanonical mode.\r
+\r
+    @param[in]    filp        Pointer to the descriptor of the device (file) to be read.\r
+    @param[in]    BufferSize  Maximum number of bytes to be returned to the caller.\r
+    @param[out]   Buffer      Pointer to the buffer where the input is to be stored.\r
+\r
+    @retval   -1    An error occurred.  No data is available.\r
+    @retval    0    No data was available.  Try again later.\r
+    @retval   >0    The number of bytes consumed by the returned data.\r
+**/\r
+static\r
+ssize_t\r
+EFIAPI\r
+IIO_Read(\r
+  struct __filedes *filp,\r
+  size_t BufferSize,\r
+  VOID *Buffer\r
+  )\r
+{\r
+  cIIO     *This;\r
+  ssize_t   NumRead;\r
+  tcflag_t  Flags;\r
+  size_t    XlateSz;\r
+  size_t    Needed;\r
+\r
+  NumRead = -1;\r
+  This = filp->devdata;\r
+  if(This != NULL) {\r
+    Flags = This->Termio.c_lflag;\r
+    if(Flags & ICANON) {\r
+      NumRead = IIO_CanonRead(filp);\r
+    }\r
+    else {\r
+      NumRead = IIO_NonCanonRead(filp);\r
+    }\r
+    // At this point, the input has been accumulated in the input buffer.\r
+    if(filp->f_iflags & _S_IWTTY) {\r
+      // Data in InBuf is wide characters.  Convert to MBCS\r
+      // First, convert into a linear buffer\r
+      NumRead = This->InBuf->Copy(This->InBuf, gMD->UString2, (INT32)UNICODE_STRING_MAX-1);\r
+      gMD->UString2[NumRead] = 0;   // Ensure that the buffer is terminated\r
+      // Determine the needed space\r
+      XlateSz = EstimateWtoM((const wchar_t *)gMD->UString2, BufferSize, &Needed);\r
+\r
+      // Now translate this into MBCS in Buffer\r
+      NumRead = wcstombs((char *)Buffer, (const wchar_t *)gMD->UString2, XlateSz);\r
+\r
+      // Consume the translated characters\r
+      (void)This->InBuf->Flush(This->InBuf, Needed);\r
+    }\r
+    else {\r
+      // Data in InBuf is narrow characters.  Use verbatim.\r
+      NumRead = This->InBuf->Read(This->InBuf, Buffer, (INT32)BufferSize);\r
+    }\r
+  }\r
+  return NumRead;\r
+}\r
+\r
+/** Process characters from buffer buf and write them to the output device\r
+    specified by filp.\r
+\r
+    @param[in]      filp      Pointer to a file descriptor structure.\r
+    @param[in]      buf       Pointer to the MBCS string to be output.\r
+    @param[in]      N         Number of bytes in buf.\r
+\r
+    @retval   >=0    Number of bytes sent to the output device.\r
+**/\r
+static\r
+ssize_t\r
+EFIAPI\r
+IIO_Write(\r
+  struct __filedes *filp,\r
+  const char *buf,\r
+  ssize_t N\r
+  )\r
+{\r
+  cIIO       *This;\r
+  cFIFO      *OutBuf;\r
+  mbstate_t  *OutState;\r
+  char       *MbcsPtr;\r
+  ssize_t     NumWritten;\r
+  ssize_t     NumProc;\r
+  size_t      CharLen;\r
+  UINTN       MaxColumn;\r
+  UINTN       MaxRow;\r
+  wchar_t     OutChar[2];     // Just in case we run into 4-byte MBCS character\r
+  int         OutMode;\r
+\r
+  errno = 0;          // indicate no error as default\r
+  NumWritten = -1;\r
+\r
+  /* Determine what the current screen size is. Also validates the output device. */\r
+  OutMode = IIO_GetOutputSize(filp->MyFD, &MaxColumn, &MaxRow);\r
+\r
+  This = filp->devdata;\r
+  if((This != NULL) && (OutMode >= 0)) {\r
+    if(filp->MyFD == STDERR_FILENO) {\r
+      OutBuf = This->ErrBuf;\r
+      OutState  = &This->ErrState;\r
+    }\r
+    else {\r
+      OutBuf = This->OutBuf;\r
+      OutState  = &This->OutState;\r
+    }\r
+\r
+    /*  Set the maximum screen dimensions. */\r
+    This->MaxColumn = MaxColumn;\r
+    This->MaxRow    = MaxRow;\r
+\r
+    /*  Record where the cursor is at the beginning of the Output operation. */\r
+    (void)IIO_GetCursorPosition(filp->MyFD, &This->InitialXY.Column, &This->InitialXY.Row);\r
+    This->CurrentXY.Column  = This->InitialXY.Column;\r
+    This->CurrentXY.Row     = This->InitialXY.Row;\r
+\r
+\r
+    NumWritten = 0;\r
+    OutChar[0] = (wchar_t)buf[0];\r
+    while((OutChar[0] != 0) && (NumWritten < N)) {\r
+      CharLen = mbrtowc(OutChar, (const char *)&buf[NumWritten], MB_CUR_MAX, OutState);\r
+      NumProc = IIO_WriteOne(filp, OutBuf, OutChar[0]);\r
+      if(NumProc > 0) {\r
+        // Successfully processed and buffered one character\r
+        NumWritten += CharLen;   // Index of start of next character\r
+      }\r
+      else if(NumProc == -1) {\r
+        // Encoding Error\r
+        (void)mbrtowc(NULL, NULL, 1, OutState);  // Re-Initialize the conversion state\r
+        errno = EILSEQ;\r
+        break;\r
+      }\r
+      else {\r
+        // Last character was incomplete\r
+        break;\r
+      }\r
+    }\r
+    // At this point, the characters to write are in OutBuf\r
+    // First, linearize the buffer\r
+    NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
+    gMD->UString[NumWritten] = 0;   // Ensure that the buffer is terminated\r
+\r
+    if(filp->f_iflags & _S_IWTTY) {\r
+      // Output device expects wide characters, Output what we have\r
+      NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString);\r
+    }\r
+    else {\r
+      // Output device expects narrow characters, convert to MBCS\r
+      MbcsPtr = (char *)gMD->UString2;\r
+      // Determine the needed space\r
+      NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), &CharLen);\r
+\r
+      // Now translate this into MBCS in Buffer\r
+      NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
+      MbcsPtr[NumWritten] = 0;   // Ensure the buffer is terminated\r
+\r
+      // Send the MBCS buffer to Output\r
+      NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr);\r
+    }\r
+    // Consume the translated characters\r
+    (void)OutBuf->Flush(OutBuf, NumWritten);\r
+  }\r
+  else {\r
+    if(This == NULL) {\r
+      errno = EINVAL;\r
+    }\r
+    // Otherwise, errno is already set.\r
+  }\r
+  return NumWritten;\r
+}\r
+\r
+/** Echo a character to an output device.\r
+    Performs translation and edit processing depending upon termios flags.\r
+\r
+    @param[in]    filp      A pointer to a file descriptor structure.\r
+    @param[in]    EChar     The character to echo.\r
+    @param[in]    EchoIsOK  TRUE if the caller has determined that characters\r
+                            should be echoed.  Otherwise, just buffer.\r
+\r
+    @return   Returns the number of characters actually output.\r
+**/\r
+static\r
+ssize_t\r
+EFIAPI\r
+IIO_Echo(\r
+  struct __filedes *filp,\r
+  wchar_t           EChar,\r
+  BOOLEAN           EchoIsOK\r
+  )\r
+{\r
+  cIIO     *This;\r
+  ssize_t   NumWritten;\r
+  cFIFO    *OutBuf;\r
+  char     *MbcsPtr;\r
+  ssize_t   NumProc;\r
+  tcflag_t  LFlags;\r
+\r
+  NumWritten = -1;\r
+  This = filp->devdata;\r
+  if(This != NULL) {\r
+    OutBuf = This->OutBuf;\r
+    LFlags = This->Termio.c_lflag & (ECHOK | ECHOE);\r
+\r
+    if((EChar >= TtyFunKeyMin) && (EChar < TtyFunKeyMax)) {\r
+      // A special function key was pressed, buffer it, don't echo, and activate.\r
+      // Process and buffer the character.  May produce multiple characters.\r
+      NumProc = IIO_EchoOne(filp, EChar, FALSE);    // Don't echo this character\r
+      EChar   = CHAR_LINEFEED;                      // Every line must end with '\n' (legacy)\r
+    }\r
+    // Process and buffer the character.  May produce multiple characters.\r
+    NumProc = IIO_EchoOne(filp, EChar, EchoIsOK);\r
+\r
+    // At this point, the character(s) to write are in OutBuf\r
+    // First, linearize the buffer\r
+    NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
+    gMD->UString[NumWritten] = 0;   // Ensure that the buffer is terminated\r
+\r
+    if((EChar == IIO_ECHO_KILL) && (LFlags & ECHOE) && EchoIsOK) {\r
+      // Position the cursor to the start of input.\r
+      (void)IIO_SetCursorPosition(filp, &This->InitialXY);\r
+    }\r
+    // Output the buffer\r
+    if(filp->f_iflags & _S_IWTTY) {\r
+      // Output device expects wide characters, Output what we have\r
+      NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString);\r
+    }\r
+    else {\r
+      // Output device expects narrow characters, convert to MBCS\r
+      MbcsPtr = (char *)gMD->UString2;\r
+      // Determine the needed space\r
+      NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), NULL);\r
+\r
+      // Now translate this into MBCS in Buffer\r
+      NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
+      MbcsPtr[NumWritten] = 0;   // Ensure the buffer is terminated\r
+\r
+      // Send the MBCS buffer to Output\r
+      NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr);\r
+    }\r
+    // Consume the echoed characters\r
+    (void)OutBuf->Flush(OutBuf, NumWritten);\r
+\r
+    if(EChar == IIO_ECHO_KILL) {\r
+      if(LFlags == ECHOK) {\r
+        NumWritten = IIO_WriteOne(filp, OutBuf, CHAR_LINEFEED);\r
+      }\r
+      else if((LFlags & ECHOE) && EchoIsOK) {\r
+        // Position the cursor to the start of input.\r
+        (void)IIO_SetCursorPosition(filp, &This->InitialXY);\r
+      }\r
+      NumWritten = 0;\r
+    }\r
+  }\r
+  else {\r
+    errno = EINVAL;\r
+  }\r
+\r
+  return NumWritten;\r
+}\r
+\r
+static\r
+void\r
+FifoDelete(cFIFO *Member)\r
+{\r
+  if(Member != NULL) {\r
+    Member->Delete(Member);\r
+  }\r
+}\r
+\r
+/** Destructor for an IIO instance.\r
+\r
+    Releases all resources used by a particular IIO instance.\r
+**/\r
+static\r
+void\r
+EFIAPI\r
+IIO_Delete(\r
+  cIIO *Self\r
+  )\r
+{\r
+  if(Self != NULL) {\r
+    FifoDelete(Self->ErrBuf);\r
+    FifoDelete(Self->OutBuf);\r
+    FifoDelete(Self->InBuf);\r
+    if(Self->AttrBuf != NULL) {\r
+      FreePool(Self->AttrBuf);\r
+    }\r
+    FreePool(Self);\r
+  }\r
+}\r
+\r
+/** Constructor for new IIO instances.\r
+\r
+    @return   Returns NULL or a pointer to a new IIO instance.\r
+**/\r
+cIIO *\r
+EFIAPI\r
+New_cIIO(void)\r
+{\r
+  cIIO     *IIO;\r
+  cc_t     *TempBuf;\r
+  int       i;\r
+\r
+  IIO = (cIIO *)AllocateZeroPool(sizeof(cIIO));\r
+  if(IIO != NULL) {\r
+    IIO->InBuf    = New_cFIFO(MAX_INPUT, sizeof(wchar_t));\r
+    IIO->OutBuf   = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t));\r
+    IIO->ErrBuf   = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t));\r
+    IIO->AttrBuf  = (UINT8 *)AllocateZeroPool(MAX_OUTPUT);\r
+\r
+    if((IIO->InBuf   == NULL) || (IIO->OutBuf   == NULL) ||\r
+       (IIO->ErrBuf  == NULL) || (IIO->AttrBuf  == NULL))\r
+    {\r
+      IIO_Delete(IIO);\r
+      IIO = NULL;\r
+    }\r
+    else {\r
+      IIO->Delete = IIO_Delete;\r
+      IIO->Read   = IIO_Read;\r
+      IIO->Write  = IIO_Write;\r
+      IIO->Echo   = IIO_Echo;\r
+    }\r
+    // Initialize Termio member\r
+    TempBuf = &IIO->Termio.c_cc[0];\r
+    TempBuf[0] = 8;                 // Default length for TABs\r
+    for(i=1; i < NCCS; ++i) {\r
+      TempBuf[i] = _POSIX_VDISABLE;\r
+    }\r
+    TempBuf[VMIN]         = 0;\r
+    TempBuf[VTIME]        = 0;\r
+    IIO->Termio.c_ispeed  = B115200;\r
+    IIO->Termio.c_ospeed  = B115200;\r
+    IIO->Termio.c_iflag   = ICRNL;\r
+    IIO->Termio.c_oflag   = OPOST | ONLCR | ONOCR | ONLRET;\r
+    IIO->Termio.c_cflag   = 0;\r
+    IIO->Termio.c_lflag   = ECHO | ECHONL;\r
+  }\r
+  return IIO;\r
+}\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIO.inf b/StdLib/LibC/Uefi/InteractiveIO/IIO.inf
new file mode 100644 (file)
index 0000000..dd21e85
--- /dev/null
@@ -0,0 +1,51 @@
+## @file\r
+#  Interactive I/O Library.\r
+#\r
+#  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+#  This program and the accompanying materials are licensed and made available\r
+#  under the terms and conditions of the BSD License which accompanies this\r
+#  distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php.\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                   = 0x00010005\r
+  BASE_NAME                     = LibIIO\r
+  FILE_GUID                     = c1e9fffb-5557-4cb5-a5f5-1fbd902a74ed\r
+  MODULE_TYPE                   = UEFI_APPLICATION\r
+  VERSION_STRING                = 1.0\r
+  LIBRARY_CLASS                 = LibIIO\r
+\r
+#\r
+#  VALID_ARCHITECTURES          = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  IIO.c\r
+  NonCanonRead.c\r
+  CanonRead.c\r
+  TerminalFunctions.c\r
+  IIOutilities.c\r
+  IIOwrite.c\r
+  IIOecho.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  StdLib/StdLib.dec\r
+  StdLibPrivateInternalFiles/DoNotUse.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  MemoryAllocationLib\r
+  LibC\r
+  LibWchar\r
+  LibContainer\r
+\r
+[Protocols]\r
+  gEfiSimpleTextInProtocolGuid          ## CONSUMES\r
+  gEfiSimpleTextOutProtocolGuid         ## CONSUMES\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOecho.c b/StdLib/LibC/Uefi/InteractiveIO/IIOecho.c
new file mode 100644 (file)
index 0000000..14369de
--- /dev/null
@@ -0,0 +1,141 @@
+/** @file\r
+  Echo characters to an Interactive I/O Output device.\r
+\r
+  The functions assume that isatty() is TRUE at the time they are called.\r
+  Since the UEFI console is a WIDE character device, these functions do all\r
+  processing using wide characters.\r
+\r
+  It is the responsibility of the caller, or higher level function, to perform\r
+  any necessary translation between wide and narrow characters.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <assert.h>\r
+#include  <errno.h>\r
+#include  <sys/termios.h>\r
+#include  <Device/IIO.h>\r
+#include  "IIOutilities.h"\r
+#include  "IIOechoCtrl.h"\r
+\r
+/** Echo one character to an IIO file.\r
+\r
+    If character InCh is a special "echo control" character, process it and output\r
+    the resultant character(s), if any.  Otherwise pass the character on to the\r
+    IIO_WriteOne() function which performs generic output processing, if needed.\r
+\r
+    @param[in]    filp        Pointer to an open IIO file's file descriptor structure.\r
+    @param[in]    InCh        The wide character to be echoed.\r
+    @param[in]    EchoIsOK    A flag indicating whether echoing is appropriate for this\r
+                              device or not.\r
+\r
+    @retval   -1    The filp argument does not refer to an IIO device.\r
+                    Global value errno is set to EINVAL.\r
+    @retval   >=0   The number of characters actually output.\r
+\r
+    @sa   IIO_WriteOne\r
+**/\r
+ssize_t\r
+IIO_EchoOne (\r
+  struct __filedes     *filp,\r
+  wchar_t               InCh,\r
+  BOOLEAN               EchoIsOK\r
+  )\r
+{\r
+  cIIO       *This;\r
+  cFIFO      *OutBuf;\r
+  cFIFO      *InBuf;\r
+  UINT8      *AttrBuf;\r
+  ssize_t     NumEcho;\r
+  tcflag_t    LFlags;\r
+  UINT32      AttrDex;\r
+  int         i;\r
+\r
+  NumEcho = -1;\r
+  This    = filp->devdata;\r
+\r
+  if(This != NULL) {\r
+    LFlags  = This->Termio.c_lflag;\r
+    OutBuf  = This->OutBuf;\r
+    InBuf   = This->InBuf;\r
+    AttrBuf = This->AttrBuf;\r
+    AttrDex = InBuf->GetWDex(InBuf);\r
+\r
+    switch(InCh) {\r
+      case IIO_ECHO_DISCARD:\r
+        // Do not buffer or otherwise process\r
+        NumEcho = 0;\r
+        break;\r
+\r
+      case IIO_ECHO_ERASE:\r
+        // Delete last character from InBuf\r
+        if(!InBuf->IsEmpty(InBuf)) {\r
+          (void)InBuf->Truncate(InBuf);\r
+\r
+          // Erase screen character(s) based on Attrib value\r
+          if(LFlags & ECHO) {\r
+            AttrDex = (UINT32)ModuloDecrement(AttrDex, InBuf->NumElements);\r
+            NumEcho = AttrBuf[AttrDex];\r
+            for(i = 0; i < NumEcho; ++i) {\r
+              (void)IIO_WriteOne(filp, OutBuf, CHAR_BACKSPACE);\r
+            }\r
+            if(LFlags & ECHOE) {\r
+              for(i = 0; i < NumEcho; ++i) {\r
+                (void)IIO_WriteOne(filp, OutBuf, L' ');\r
+              }\r
+              for(i = 0; i < NumEcho; ++i) {\r
+                (void)IIO_WriteOne(filp, OutBuf, CHAR_BACKSPACE);\r
+              }\r
+            }\r
+          }\r
+          else {\r
+            NumEcho = 0;\r
+          }\r
+        }\r
+        break;\r
+\r
+      case IIO_ECHO_KILL:\r
+        // Flush contents of InBuf and OutBuf\r
+        InBuf->Flush(InBuf, (size_t)-1);\r
+        OutBuf->Flush(OutBuf, (size_t)-1);\r
+\r
+        // Erase characters from screen.\r
+        if(LFlags & ECHOE) {\r
+          NumEcho = IIO_CursorDelta(This, &This->InitialXY, &This->CurrentXY);\r
+          for(i = 0; i < NumEcho; ++i) {\r
+            (void)IIO_WriteOne(filp, OutBuf, L' ');\r
+          }\r
+        }\r
+        break;\r
+\r
+      default:\r
+        // Add character to input buffer\r
+        (void)InBuf->Write(InBuf, &InCh, 1);\r
+\r
+        NumEcho = 0;  // In case echoing is not enabled or OK\r
+        // If echoing is OK and enabled, "echo" character using IIO_WriteOne\r
+        if( EchoIsOK                &&\r
+            ( (LFlags & ECHO)       ||\r
+              ((LFlags & ECHONL) && (InCh == CHAR_LINEFEED))))\r
+        {\r
+          NumEcho = IIO_WriteOne(filp, OutBuf, InCh);\r
+        }\r
+        AttrBuf[AttrDex] = (UINT8)NumEcho;\r
+        break;\r
+    }\r
+  }\r
+  else {\r
+    errno = EINVAL;\r
+  }\r
+  return NumEcho;\r
+}\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h b/StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h
new file mode 100644 (file)
index 0000000..69d040a
--- /dev/null
@@ -0,0 +1,33 @@
+/** @file\r
+  Constants and declarations for the Echo function.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#ifndef _IIO_ECHO_CTRL_H\r
+#define _IIO_ECHO_CTRL_H\r
+#include  <sys/termios.h>\r
+\r
+__BEGIN_DECLS\r
+\r
+/* These constants are assigned values within the Unicode Private Use range.\r
+   The value of IIO_ECHO_MIN must be adjusted to ensure that IIO_ECHO_MAX\r
+   never exceeds the value of 0xF900.\r
+*/\r
+typedef enum {\r
+  IIO_ECHO_MIN      = (TtyFunKeyMin - 3),\r
+  IIO_ECHO_DISCARD  = IIO_ECHO_MIN,       // Ignore this character completely\r
+  IIO_ECHO_ERASE,                         // Erase previous character\r
+  IIO_ECHO_KILL,                          // Kill the entire line\r
+  IIO_ECHO_MAX\r
+} IioEchoCtrl;\r
+\r
+__END_DECLS\r
+\r
+#endif  /* _IIO_ECHO_CTRL_H */\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c b/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c
new file mode 100644 (file)
index 0000000..2da0628
--- /dev/null
@@ -0,0 +1,288 @@
+/** @file\r
+  Utilities for Interactive I/O Functions.\r
+\r
+  The functions assume that isatty() is TRUE at the time they are called.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+#include  <Protocol/SimpleTextOut.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <assert.h>\r
+#include  <errno.h>\r
+#include  <sys/syslimits.h>\r
+#include  <sys/termios.h>\r
+#include  <Device/IIO.h>\r
+#include  <MainData.h>\r
+#include  "IIOutilities.h"\r
+\r
+/** Get the low-level UEFI protocol associated with an open file.\r
+\r
+    @param[in]    fd    File descriptor for an open file.\r
+    @param[out]   filp  NULL, or a pointer to where a pointer to the file's\r
+                        file descriptor structure is to be stored.\r
+\r
+    @return   Returns NULL if fd is not a valid file descriptor, otherwise\r
+              a pointer to the file's associated UEFI protocol is returned.\r
+**/\r
+void *\r
+EFIAPI\r
+IIO_GetDeviceProto (\r
+  int                 fd,\r
+  struct __filedes  **filp\r
+  )\r
+{\r
+  void               *Proto;\r
+  ConInstance        *Stream;\r
+  struct __filedes   *pfil;\r
+\r
+  Proto = NULL;\r
+  if(ValidateFD( fd, VALID_OPEN)) {\r
+    pfil = &gMD->fdarray[fd];\r
+    Stream = BASE_CR(pfil->f_ops, ConInstance, Abstraction);\r
+    Proto = (void *)Stream->Dev;\r
+    if(filp != NULL) {\r
+      *filp = pfil;\r
+    }\r
+  }\r
+  return Proto;\r
+}\r
+\r
+/** Get a character either from the input buffer or from hardware.\r
+\r
+    @param[in]    filp      Pointer to a file descriptor structure.\r
+    @param[in]    First     Set to TRUE to identify the initial read.\r
+\r
+    @return   Returns a character read from either the input buffer\r
+              or from the open file (device) identified by filp.\r
+              A return value of WEOF indicates an error has occurred.\r
+**/\r
+wint_t\r
+EFIAPI\r
+IIO_GetInChar (\r
+  struct __filedes *filp,\r
+  BOOLEAN           First\r
+)\r
+{\r
+  cIIO             *This;\r
+  cFIFO            *InBuf;\r
+  EFI_STATUS        Status;\r
+  ssize_t           NumRead;\r
+  wint_t            RetVal;\r
+  wchar_t           InChar;\r
+\r
+  static size_t     BufCnt;\r
+\r
+  This      = filp->devdata;\r
+  InBuf     = This->InBuf;\r
+\r
+  NumRead = -1;\r
+  InChar  =  0;\r
+  if(First) {\r
+    BufCnt = InBuf->Count(InBuf, AsElements);\r
+  }\r
+  if(BufCnt > 0) {\r
+    Status = InBuf->Read(InBuf, &InChar, 1);\r
+    --BufCnt;\r
+    NumRead = 1;\r
+  }\r
+  else {\r
+    NumRead = filp->f_ops->fo_read(filp, &filp->f_offset, sizeof(wchar_t), &InChar);\r
+  }\r
+  if(NumRead <= 0) {\r
+    RetVal = WEOF;\r
+  }\r
+  else {\r
+    RetVal = (wint_t)InChar;\r
+  }\r
+  return InChar;\r
+}\r
+\r
+/** Get the current cursor position.\r
+\r
+    @param[in]      fd      File descriptor for an open file.\r
+    @param[out]     Column  Pointer to where the current cursor column is to be stored.\r
+    @param[out]     Row     Pointer to where the current cursor row is to be stored.\r
+\r
+    @retval   -1    fd is not an IIO output device.\r
+    @retval    0    Cursor position retrieved, Cursor is Not Visible.\r
+    @retval    1    Cursor position retrieved, Cursor is Visible.\r
+**/\r
+int\r
+EFIAPI\r
+IIO_GetCursorPosition (\r
+  int       fd,\r
+  UINT32   *Column,\r
+  UINT32   *Row\r
+  )\r
+{\r
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;\r
+  struct __filedes                   *pStdOut;\r
+  int                                 RetVal;\r
+\r
+  RetVal    = -1;\r
+\r
+  Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(fd, &pStdOut);\r
+  if(Proto != NULL) {\r
+    if(((pStdOut->f_iflags & _S_ITTY) != 0) &&    // file is a TTY\r
+       ((pStdOut->Oflags & O_ACCMODE) != 0))      // and it is open for output\r
+    {\r
+      // fd is for a TTY or "Interactive IO" device\r
+      *Column  = Proto->Mode->CursorColumn;\r
+      *Row     = Proto->Mode->CursorRow;\r
+      if(Proto->Mode->CursorVisible) {\r
+        RetVal = 1;\r
+      }\r
+      else {\r
+        RetVal = 0;\r
+      }\r
+    }\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Set the cursor position.\r
+\r
+    @param[in]    filp    Pointer to the output device's file descriptor structure.\r
+    @param[in]    StartXY Pointer to a cursor coordinate (XY) structure indicating\r
+                          the desired coordinate to move the cursor to.\r
+\r
+    @retval   -1    fd is not an IIO output device\r
+    @retval    0    Cursor position set successfully.\r
+**/\r
+int\r
+EFIAPI\r
+IIO_SetCursorPosition (\r
+  struct __filedes *filp,\r
+  CURSOR_XY        *CursorXY\r
+  )\r
+{\r
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;\r
+  cIIO                               *This;\r
+  EFI_STATUS                          Status;\r
+  int                                 RetVal;\r
+\r
+  RetVal    = -1;\r
+\r
+  This = filp->devdata;\r
+  Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(filp->MyFD, NULL);\r
+  if(Proto != NULL) {\r
+    if(((filp->f_iflags & _S_ITTY) != 0) &&    // file is a TTY\r
+       ((filp->Oflags & O_ACCMODE) != 0))      // and it is open for output\r
+    {\r
+      // fd is for a TTY or "Interactive IO" device\r
+      Status = Proto->SetCursorPosition(Proto, CursorXY->Column, CursorXY->Row);\r
+      if(Status == EFI_SUCCESS) {\r
+        This->CurrentXY.Column  = CursorXY->Column;\r
+        This->CurrentXY.Row     = CursorXY->Row;\r
+        RetVal = 0;\r
+      }\r
+    }\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Get Output screen size and mode.\r
+\r
+    @param[in]    fd    File descriptor of the output device.\r
+    @param[out]   Col   Pointer to where to store the MAX Column, or NULL.\r
+    @param[out]   Row   Pointer to where to store the MAX Row, or NULL.\r
+\r
+    @retval   <0    An error occurred.  The reason is in errno and EFIerrno.\r
+                      * EIO     UEFI QueryMode failed\r
+                      * ENOTTY  fd does not refer to an interactive output device\r
+    @retval   >=0   Current output mode\r
+**/\r
+int\r
+EFIAPI\r
+IIO_GetOutputSize (\r
+  int       fd,\r
+  UINTN    *Col,\r
+  UINTN    *Row\r
+)\r
+{\r
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;\r
+  struct __filedes                   *pStdOut;\r
+  EFI_STATUS                          Status;\r
+  UINTN                               TempCol;\r
+  UINTN                               TempRow;\r
+  UINTN                               TempMode;\r
+  int                                 RetVal;\r
+\r
+  RetVal    = -1;\r
+\r
+  Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(fd, &pStdOut);\r
+  if(Proto != NULL) {\r
+    if(((pStdOut->f_iflags & _S_ITTY) != 0)   &&    // file is a TTY\r
+        ((pStdOut->Oflags & O_ACCMODE) != 0))       // and it is open for output\r
+    {\r
+      // fd is for a TTY or "Interactive IO" device\r
+      TempMode = Proto->Mode->Mode;\r
+      Status = Proto->QueryMode(Proto, TempMode, &TempCol, &TempRow);\r
+      if(EFI_ERROR(Status)) {\r
+        EFIerrno  = Status;\r
+        errno     = EIO;\r
+      }\r
+      else {\r
+        *Col    = TempCol;\r
+        *Row    = TempRow;\r
+        RetVal  = (int)TempMode;\r
+      }\r
+    }\r
+    else {\r
+      errno = ENOTTY;\r
+    }\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Calculate the number of character positions between two X/Y coordinate pairs.\r
+\r
+    Using the current output device characteristics, calculate the number of\r
+    characters between two coordinates.  It is assumed that EndXY points to\r
+    an output location that occurs after StartXY.\r
+\r
+    RowDelta is the computed difference between the ending and starting rows.\r
+    If RowDelta < 0, then EndXY is NOT after StartXY, so assert.\r
+\r
+    ColumnDelta is the computed number of character positions (columns) between\r
+    the starting position and the ending position.  If ColumnDelta is < 0,\r
+    then EndXY is NOT after StartXY, so assert.\r
+\r
+    @param[in]      This      Pointer to the IIO instance to be examined.\r
+    @param[in]      StartXY   Pointer to the starting coordinate pair.\r
+    @param[in]      EndXY     Pointer to the ending coordinate pair.\r
+\r
+    @return   Returns the difference between the starting and ending coordinates.\r
+**/\r
+UINT32\r
+EFIAPI\r
+IIO_CursorDelta (\r
+  cIIO         *This,\r
+  CURSOR_XY    *StartXY,\r
+  CURSOR_XY    *EndXY\r
+)\r
+{\r
+  INT32    ColumnDelta;\r
+  INT32    RowDelta;\r
+\r
+  RowDelta = (int)EndXY->Row - (int)StartXY->Row;\r
+\r
+  assert(RowDelta >= 0);    // assert if EndXY is NOT after StartXY\r
+\r
+  ColumnDelta = (INT32)((This->MaxColumn * RowDelta) + EndXY->Column);\r
+  ColumnDelta -= (INT32)StartXY->Column;\r
+\r
+  assert(ColumnDelta >= 0); // assert if EndXY is NOT after StartXY\r
+\r
+  return (UINT32)ColumnDelta;\r
+}\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h b/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h
new file mode 100644 (file)
index 0000000..778b612
--- /dev/null
@@ -0,0 +1,129 @@
+/** @file\r
+  Utilities for Interactive I/O Functions.\r
+\r
+  The functions assume that isatty() is TRUE at the time they are called.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#ifndef _IIO_UTILITIES_H\r
+#define _IIO_UTILITIES_H\r
+\r
+#include  <sys/EfiSysCall.h>\r
+\r
+__BEGIN_DECLS\r
+\r
+/** Get the low-level UEFI protocol associated with an open file.\r
+\r
+    @param[in]    fd    File descriptor for an open file.\r
+    @param[out]   filp  NULL, or a pointer to where a pointer to the file's\r
+                        file descriptor structure is to be stored.\r
+\r
+    @return   Returns NULL if fd is not a valid file descriptor, otherwise\r
+              a pointer to the file's associated UEFI protocol is returned.\r
+**/\r
+void *\r
+EFIAPI\r
+IIO_GetDeviceProto (\r
+  int                 fd,\r
+  struct __filedes  **filp    // Optional - filp == NULL if unused\r
+  );\r
+\r
+/** Get a character either from the input buffer or from hardware.\r
+\r
+    @param[in]    filp      Pointer to a file descriptor structure.\r
+    @param[in]    First     Set to TRUE to identify the initial read.\r
+\r
+    @return   Returns a character read from either the input buffer\r
+              or from the open file (device) identified by filp.\r
+              A return value of WEOF indicates an error has occurred.\r
+**/\r
+wint_t\r
+EFIAPI\r
+IIO_GetInChar (\r
+  struct __filedes *filp,\r
+  BOOLEAN           First\r
+  );\r
+\r
+/** Get the current cursor position.\r
+\r
+    @param[in]      fd      File descriptor for an open file.\r
+    @param[out]     Column  Pointer to where the current cursor column is to be stored.\r
+    @param[out]     Row     Pointer to where the current cursor row is to be stored.\r
+\r
+    @retval   -1    fd is not an IIO output device.\r
+    @retval    0    Cursor position retrieved, Cursor is Not Visible.\r
+    @retval    1    Cursor position retrieved, Cursor is Visible.\r
+**/\r
+int\r
+EFIAPI\r
+IIO_GetCursorPosition (\r
+  int       fd,\r
+  UINT32   *Column,\r
+  UINT32   *Row\r
+  );\r
+\r
+/** Set the cursor position.\r
+\r
+    @param[in]    filp    Pointer to the output device's file descriptor structure.\r
+    @param[in]    StartXY Pointer to a cursor coordinate (XY) structure indicating\r
+                          the desired coordinate to move the cursor to.\r
+\r
+    @retval   -1    fd is not an IIO output device\r
+    @retval    0    Cursor position set successfully.\r
+**/\r
+int\r
+EFIAPI\r
+IIO_SetCursorPosition (\r
+  struct __filedes *filp,\r
+  CURSOR_XY        *StartXY\r
+  );\r
+\r
+/** Get Output screen size and mode.\r
+\r
+    @param[in]    fd    File descriptor of the output device.\r
+    @param[out]   Col   Pointer to where to store the MAX Column, or NULL.\r
+    @param[out]   Row   Pointer to where to store the MAX Row, or NULL.\r
+\r
+    @retval   <0    An error occurred.  The reason is in errno and EFIerrno.\r
+                      * EIO     UEFI QueryMode failed\r
+                      * ENOTTY  fd does not refer to an interactive output device\r
+    @retval   >=0   Current output mode\r
+**/\r
+int\r
+EFIAPI\r
+IIO_GetOutputSize (\r
+  int       fd,\r
+  UINTN    *Col,\r
+  UINTN    *Row\r
+);\r
+\r
+/** Calculate the number of character positions between two X/Y coordinate pairs.\r
+\r
+    Using the current output device characteristics, calculate the number of\r
+    characters between two coordinates.\r
+\r
+    @param[in]      This      Pointer to the IIO instance to be examined.\r
+    @param[in]      StartXY   Pointer to the starting coordinate pair.\r
+    @param[in]      EndXY     Pointer to the ending coordinate pair.\r
+\r
+    @return   Returns the difference between the starting and ending coordinates.\r
+              The return value is positive if the coordinates contained in EndXY\r
+              are larger than StartXY, otherwise the return value is negative.\r
+**/\r
+int\r
+EFIAPI\r
+IIO_CursorDelta (\r
+  cIIO         *This,\r
+  CURSOR_XY    *StartXY,\r
+  CURSOR_XY    *EndXY\r
+  );\r
+\r
+__END_DECLS\r
+#endif  /* _IIO_UTILITIES_H */\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c b/StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c
new file mode 100644 (file)
index 0000000..927f4f4
--- /dev/null
@@ -0,0 +1,210 @@
+/** @file\r
+  Write to an Interactive I/O Output device.\r
+\r
+  The functions assume that isatty() is TRUE at the time they are called.\r
+  Since the UEFI console is a WIDE character device, these functions do all\r
+  processing using wide characters.\r
+\r
+  It is the responsibility of the caller, or higher level function, to perform\r
+  any necessary translation between wide and narrow characters.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <assert.h>\r
+#include  <errno.h>\r
+#include  <sys/termios.h>\r
+#include  <Device/IIO.h>\r
+\r
+static wchar_t  Spaces[] = L"                ";   // Spaces for expanding TABs\r
+\r
+#define MAX_TAB_WIDTH     ((int)(sizeof(Spaces) / sizeof(wchar_t)) - 1)\r
+\r
+#define MAX_EXPANSION     3\r
+\r
+/** Process and buffer one character for output.\r
+\r
+    @param[in]    filp      Pointer to a file descriptor structure.\r
+    @param[out]   OBuf      Pointer to the Output Buffer FIFO.\r
+    @param[in]    InCh      The wide character to process.\r
+\r
+    @retval   <0    An error occurred.  Reason is in errno.\r
+                      * EINVAL  The pointer to the IIO object is NULL.\r
+                      * ENOSPC  The OBuf FIFO is full.\r
+\r
+    @retval    0    A character was input but not placed in the output buffer.\r
+\r
+    @retval   >0    The number of characters buffered.  Normally 1, or 2.\r
+                    If a character is discarded because of flag settings, a\r
+                    1 will be returned.\r
+**/\r
+ssize_t\r
+IIO_WriteOne(struct __filedes *filp, cFIFO *OBuf, wchar_t InCh)\r
+{\r
+  cIIO               *This;\r
+  struct termios     *Termio;\r
+  tcflag_t            OFlag;\r
+  ssize_t             RetVal;\r
+  wchar_t             wc[MAX_EXPANSION];        // Sub-buffer for conversions\r
+  wchar_t            *wcb;          // Pointer to either wc or spaces\r
+  int                 numW    = 0;  // Wide characters placed in OBuf\r
+  INT32               TabWidth;     // Each TAB expands into this number of spaces\r
+  UINT32              CurColumn;    // Current cursor column on the screen\r
+  UINT32              CurRow;       // Current cursor row on the screen\r
+  UINT32              PrevColumn;   // Previous column.  Used to detect wrapping.\r
+  UINT32              AdjColumn;    // Current cursor column on the screen\r
+  UINT32              AdjRow;       // Current cursor row on the screen\r
+\r
+  RetVal    = -1;\r
+  wcb       = wc;\r
+  This      = filp->devdata;\r
+  if((This != NULL) && (OBuf->FreeSpace(OBuf, AsElements) >= MAX_EXPANSION)) {\r
+    Termio    = &This->Termio;\r
+    OFlag     = Termio->c_oflag;\r
+    TabWidth  = (INT32)This->Termio.c_cc[VTABLEN];\r
+    if(TabWidth > MAX_TAB_WIDTH) {\r
+      TabWidth = MAX_TAB_WIDTH;\r
+    }\r
+    CurColumn = This->CurrentXY.Column;\r
+    CurRow    = This->CurrentXY.Row;\r
+\r
+    numW      = 1;          // The majority of characters buffer one character\r
+    AdjRow    = 0;          // Most characters just cause horizontal movement\r
+    AdjColumn = 0;\r
+    if(OFlag & OPOST) {\r
+      /* Perform output processing */\r
+      switch(InCh) {\r
+        case CHAR_TAB:                //{{\r
+          if(OFlag & OXTABS) {\r
+            if(TabWidth > 0) {\r
+              int   SpaceIndex;\r
+\r
+              SpaceIndex = CurColumn % TabWidth;    // Number of spaces after a Tab Stop\r
+              numW = TabWidth - SpaceIndex;         // Number of spaces to the next Tab Stop\r
+              SpaceIndex = MAX_TAB_WIDTH - numW;    // Index into the Spaces array\r
+              wcb = &Spaces[SpaceIndex];            // Point to the appropriate number of spaces\r
+            }\r
+            else {\r
+              wc[0] = L' ';\r
+            }\r
+            AdjColumn = numW;\r
+          }\r
+          else {\r
+            wc[0] = InCh;     // Send the TAB itself - assumes that it does not move cursor.\r
+          }\r
+          break;                      //}}\r
+\r
+        case CHAR_CARRIAGE_RETURN:    //{{\r
+          if((OFlag & OCRNL) == 0) {\r
+            if((OFlag & ONLRET) == 0) {\r
+              numW = 0;   /* Discard the CR */\r
+              // Cursor doesn't move\r
+            }\r
+            else {\r
+              wc[0]     = CHAR_CARRIAGE_RETURN;\r
+              CurColumn = 0;\r
+            }\r
+            break;\r
+          }\r
+          else {\r
+            InCh = CHAR_LINEFEED;\r
+          }                           //}}\r
+          // Fall through to the NL case\r
+        case CHAR_LINEFEED:           //{{\r
+          if(OFlag & ONLCR) {\r
+            wc[0] = CHAR_CARRIAGE_RETURN;\r
+            wc[1] = CHAR_LINEFEED;\r
+            numW  = 2;\r
+            CurColumn = 0;\r
+          }\r
+          AdjRow = 1;\r
+          break;                      //}}\r
+\r
+        case CHAR_BACKSPACE:          //{{\r
+          if(CurColumn > 0) {\r
+            wc[0] = CHAR_BACKSPACE;\r
+            CurColumn = (UINT32)ModuloDecrement(CurColumn, (UINT32)This->MaxColumn);\r
+          }\r
+          else {\r
+            numW = 0;   // Discard the backspace if in column 0\r
+          }\r
+          break;                      //}}\r
+\r
+        case CHAR_EOT:                //{{\r
+          if(OFlag & ONOEOT) {\r
+            numW = 0;             // Discard the EOT character\r
+            // Cursor doesn't move\r
+            break;\r
+          }                           //}}\r
+          // Fall through to default in order to potentially output "^D"\r
+        default:                      //{{\r
+          if((InCh >= 0) && (InCh < L' ')) {\r
+            // InCh contains a control character\r
+            if(OFlag & OCTRL) {\r
+              wc[1]     = InCh + L'@';\r
+              wc[0]     = L'^';\r
+              numW      = 2;\r
+              AdjColumn = 2;\r
+            }\r
+            else {\r
+              numW = 0;   // Discard.  Not a UEFI supported control character.\r
+            }\r
+          }\r
+          else {\r
+            // Regular printing character\r
+            wc[0]     = InCh;\r
+            AdjColumn = 1;\r
+          }\r
+          break;                      //}}\r
+      }\r
+      if(numW < MAX_EXPANSION) {\r
+        wc[numW] = 0;             // Terminate the sub-buffer\r
+      }\r
+      if(AdjColumn != 0) {\r
+        // Adjust the cursor position\r
+        PrevColumn = CurColumn;\r
+        CurColumn = ModuloAdd(PrevColumn, AdjColumn, (UINT32)This->MaxColumn);\r
+        if(CurColumn < PrevColumn) {\r
+          // We must have wrapped, so we are on the next Row\r
+          ++CurRow;\r
+          if(CurRow >= This->MaxRow) {\r
+            // The screen has scrolled so need to adjust Initial location.\r
+            --This->InitialXY.Row;        // Initial row has moved up one\r
+            CurRow = (UINT32)(This->MaxRow - 1);    // We stay on the bottom row\r
+          }\r
+        }\r
+      }\r
+      This->CurrentXY.Column  = CurColumn;\r
+      This->CurrentXY.Row     = CurRow;\r
+    }\r
+    else {\r
+      // Output processing disabled -- RAW output mode\r
+      wc[0] = InCh;\r
+      wc[1] = 0;\r
+    }\r
+    // Put the character(s) into the output buffer\r
+    if(numW > 0) {\r
+      (void)OBuf->Write(OBuf, (const void *)wcb, (size_t)numW);\r
+    }\r
+    RetVal = numW;\r
+  }\r
+  else {\r
+    if(This == NULL) {\r
+      errno = EINVAL;\r
+    }\r
+    else {\r
+      errno = ENOSPC;\r
+    }\r
+  }\r
+  return RetVal;\r
+}\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c b/StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c
new file mode 100644 (file)
index 0000000..15bf43e
--- /dev/null
@@ -0,0 +1,89 @@
+/** @file\r
+  NonCanonical Interactive Input Function.\r
+\r
+  The functions assume that isatty() is TRUE at the time they are called.\r
+  If _S_IWTTY is set, the device returns WIDE characters.\r
+\r
+  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <LibConfig.h>\r
+\r
+#include  <sys/syslimits.h>\r
+#include  <sys/termios.h>\r
+#include  <Device/IIO.h>\r
+#include  <Containers/Fifo.h>\r
+\r
+/** Perform a noncanonical read of input.\r
+\r
+    @param[in]    filp        Pointer to a file descriptor structure.\r
+    @param[in]    BufferSize  Maximum number of bytes to return.\r
+\r
+    @retval    -1   An error has occurred.  Reason in errno.\r
+    @retval    -1   No data returned.  None was ready.\r
+    @retval    >0   The number of elements returned\r
+**/\r
+ssize_t\r
+IIO_NonCanonRead (\r
+  struct __filedes *filp\r
+  )\r
+{\r
+  cIIO           *This;\r
+  cFIFO          *InBuf;\r
+  struct termios *Termio;\r
+  EFI_STATUS      Status;\r
+  ssize_t         NumRead;\r
+  cc_t            tioMin;\r
+  cc_t            tioTime;\r
+  UINT32          InputType;\r
+  wchar_t         InChar;     // Intermediate character buffer\r
+\r
+  NumRead = -1;\r
+  InChar  = 0;      // Initialize so compilers don't complain.\r
+  This    = filp->devdata;\r
+  Termio  = &This->Termio;\r
+  InBuf   = This->InBuf;\r
+  tioMin  = Termio->c_cc[VMIN];\r
+  tioTime = Termio->c_cc[VTIME];\r
+\r
+  if(tioMin >= MAX_INPUT) {\r
+    tioMin = MAX_INPUT;\r
+  }\r
+  /*  There are four types of processing that may be done, based on\r
+      the values of tioMin and tioTime.\r
+          Min   Time    Type\r
+          ---   ----    ----\r
+           0      0       0   Return buffer contents or 1 new char\r
+           0     >0       1   Return 0 or 1 character depending on timeout\r
+          >0      0       2   Buffer Min chars. Return BufferSize chars.\r
+          >0     >0       3   Return up to Min chars. Unless the inter-byte timer expires.\r
+\r
+    Currently, only type 0 is implemented.\r
+  */\r
+  InputType = 0;\r
+  if(tioMin   != 0)     InputType = 2;\r
+  if(tioTime  != 0)   ++InputType;\r
+  //switch(InputType) {\r
+  //  case 0:\r
+      if(InBuf->IsEmpty(InBuf)) {\r
+        NumRead = filp->f_ops->fo_read(filp, &filp->f_offset, sizeof(wchar_t), &InChar);\r
+        if(NumRead > 0) {\r
+          Status = InBuf->Write(InBuf, &InChar, 1);  // Buffer the character\r
+        }\r
+      }\r
+  //    break;\r
+  //  case 1:\r
+  //    break;\r
+  //  case 2:\r
+  //    break;\r
+  //  case 3:\r
+  //    break;\r
+  //}\r
+  return NumRead;\r
+}\r
diff --git a/StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c b/StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c
new file mode 100644 (file)
index 0000000..807ab1f
--- /dev/null
@@ -0,0 +1,285 @@
+/** @file\r
+    "Terminal" Control functions for Interactive IO.\r
+\r
+    Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+    This program and the accompanying materials are licensed and made available under\r
+    the terms and conditions of the BSD License that accompanies this distribution.\r
+    The full text of the license may be found at\r
+    http://opensource.org/licenses/bsd-license.\r
+\r
+    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+#include  <Uefi.h>\r
+#include  <Library/BaseMemoryLib.h>\r
+\r
+#include  <LibConfig.h>\r
+\r
+#include  <errno.h>\r
+#include  <sys/termios.h>\r
+#include  <Device/IIO.h>\r
+#include  <MainData.h>\r
+\r
+/** Get input baud rate.\r
+\r
+    Extracts the input baud rate from the termios structure pointed to by the\r
+    pTermios argument.\r
+\r
+    @param[in]  pTermios  A pointer to the termios structure from which to extract\r
+                          the input baud rate.\r
+\r
+    @return The value of the input speed is returned exactly as it is contained\r
+            in the termios structure, without interpretation.\r
+**/\r
+speed_t\r
+cfgetispeed (\r
+  const struct termios *pTermios\r
+  )\r
+{\r
+  return pTermios->c_ispeed;\r
+}\r
+\r
+/** Get output baud rate.\r
+\r
+    Extracts the output baud rate from the termios structure pointed to by the\r
+    pTermios argument.\r
+\r
+    @param[in]  pTermios  A pointer to the termios structure from which to extract\r
+                          the output baud rate.\r
+\r
+    @return The value of the output speed is returned exactly as it is contained\r
+            in the termios structure, without interpretation.\r
+**/\r
+speed_t\r
+cfgetospeed (\r
+  const struct termios *pTermios\r
+  )\r
+{\r
+  return pTermios->c_ospeed;\r
+}\r
+\r
+/** Set input baud rate.\r
+\r
+    Replaces the input baud rate, in the termios structure pointed to by the\r
+    pTermios argument, with the value of NewSpeed.\r
+\r
+    @param[out]   pTermios  A pointer to the termios structure into which to set\r
+                            the input baud rate.\r
+    @param[in]    NewSpeed  The new input baud rate.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EINVAL - The value of NewSpeed is outside the range of\r
+                      possible speed values as specified in <sys/termios.h>.\r
+**/\r
+int\r
+cfsetispeed (\r
+  struct termios *pTermios,\r
+  speed_t         NewSpeed\r
+  )\r
+{\r
+  int RetVal;\r
+\r
+  if(NewSpeed < B921600) {\r
+    pTermios->c_ispeed = NewSpeed;\r
+    RetVal = 0;\r
+  }\r
+  else {\r
+    RetVal = -1;\r
+    errno = EINVAL;\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Set output baud rate.\r
+\r
+    Replaces the output baud rate, in the termios structure pointed to by the\r
+    pTermios argument, with the value of NewSpeed.\r
+\r
+    @param[out]   pTermios  A pointer to the termios structure into which to set\r
+                            the output baud rate.\r
+    @param[in]    NewSpeed  The new output baud rate.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EINVAL - The value of NewSpeed is outside the range of\r
+                      possible speed values as specified in <sys/termios.h>.\r
+**/\r
+int\r
+cfsetospeed (\r
+  struct termios *pTermios,\r
+  speed_t         NewSpeed\r
+  )\r
+{\r
+  int RetVal;\r
+\r
+  if(NewSpeed < B921600) {\r
+    pTermios->c_ospeed = NewSpeed;\r
+    RetVal = 0;\r
+  }\r
+  else {\r
+    RetVal = -1;\r
+    errno = EINVAL;\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Get the parameters associated with an interactive IO device.\r
+\r
+    Get the parameters associated with the device referred to by\r
+    fd and store them into the termios structure referenced by pTermios.\r
+\r
+    @param[in]    fd        The file descriptor for an open interactive IO device.\r
+    @param[out]   pTermios  A pointer to a termios structure into which to store\r
+                            attributes of the interactive IO device.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EBADF - The fd argument is not a valid file descriptor.\r
+                    * ENOTTY - The file associated with fd is not an interactive IO device.\r
+**/\r
+int\r
+tcgetattr (\r
+  int             fd,\r
+  struct termios *pTermios\r
+  )\r
+{\r
+  cIIO             *IIO;\r
+  int               RetVal;\r
+  struct __filedes *filp;\r
+  struct termios   *Termio;\r
+\r
+  RetVal = 0;\r
+  if(ValidateFD( fd, VALID_OPEN)) {\r
+    filp = &gMD->fdarray[fd];\r
+\r
+    if((filp->f_iflags & _S_ITTY) != 0) {\r
+      // fd is for a TTY or "Interactive IO" device\r
+      IIO = (cIIO *)filp->devdata;\r
+      Termio = &IIO->Termio;\r
+      (void)CopyMem((void *)pTermios, (const void *)Termio, sizeof(struct termios));\r
+    }\r
+    else {\r
+      errno   = ENOTTY;\r
+      RetVal  = -1;\r
+    }\r
+  }\r
+  else {\r
+    errno   = EBADF;\r
+    RetVal  = -1;\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Set the parameters associated with an interactive IO device.\r
+\r
+    Set the parameters associated with the device referred to by\r
+    fd to the values in the termios structure referenced by pTermios.\r
+\r
+    Behavior is modified by the value of the OptAct parameter:\r
+      * TCSANOW: The change shall occur immediately.\r
+      * TCSADRAIN: The change shall occur after all output written to fd is\r
+        transmitted. This action should be used when changing parameters which\r
+        affect output.\r
+      * TCSAFLUSH: The change shall occur after all output written to fd is\r
+        transmitted, and all input so far received but not read shall be\r
+        discarded before the change is made.\r
+\r
+    @param[in]  fd        The file descriptor for an open interactive IO device.\r
+    @param[in]  OptAct    Currently has no effect.\r
+    @param[in]  pTermios  A pointer to a termios structure into which to retrieve\r
+                          attributes to set in the interactive IO device.\r
+\r
+    @retval 0     The operation completed successfully.\r
+    @retval -1    An error occured and errno is set to indicate the error.\r
+                    * EBADF - The fd argument is not a valid file descriptor.\r
+                    * ENOTTY - The file associated with fd is not an interactive IO device.\r
+**/\r
+int\r
+tcsetattr (\r
+  int                   fd,\r
+  int                   OptAct,   // Currently ignored\r
+  const struct termios *pTermios\r
+  )\r
+{\r
+  cIIO             *IIO;\r
+  int               RetVal;\r
+  struct __filedes *filp;\r
+  struct termios   *Termio;\r
+\r
+  RetVal = 0;\r
+  if(ValidateFD( fd, VALID_OPEN)) {\r
+    filp = &gMD->fdarray[fd];\r
+\r
+    if((filp->f_iflags & _S_ITTY) != 0) {\r
+      // fd is for a TTY or "Interactive IO" device\r
+      IIO = (cIIO *)filp->devdata;\r
+      Termio = &IIO->Termio;\r
+      (void)CopyMem((void *)Termio, (const void *)pTermios, sizeof(struct termios));\r
+    }\r
+    else {\r
+      errno   = ENOTTY;\r
+      RetVal  = -1;\r
+    }\r
+  }\r
+  else {\r
+    errno   = EBADF;\r
+    RetVal  = -1;\r
+  }\r
+  return RetVal;\r
+}\r
+\r
+/** Transmit pending output.\r
+\r
+    Function is not yet implemented for UEFI.\r
+\r
+    @param[in]  fd        Ignored\r
+\r
+    @retval -1    This function is not yet supported.  errno is set to ENOTSUP.\r
+**/\r
+int\r
+tcdrain (int fd)\r
+{\r
+  errno = ENOTSUP;\r
+  return -1;\r
+}\r
+\r
+/** Suspend or restart the transmission or reception of data.\r
+\r
+    This function will suspend or resume transmission or reception of data on\r
+    the file referred to by fd, depending on the value of Action.\r
+\r
+    Function is not yet implemented for UEFI.\r
+\r
+    @param[in]  fd        Ignored\r
+    @param[in]  Action    Ignored\r
+\r
+    @retval -1    This function is not yet supported.  errno is set to ENOTSUP.\r
+**/\r
+int\r
+tcflow (\r
+  int fd,\r
+  int Action)\r
+{\r
+  errno = ENOTSUP;\r
+  return -1;\r
+}\r
+\r
+/** Discard non-transmitted output data, non-read input data, or both.\r
+\r
+    Function is not yet implemented for UEFI.\r
+\r
+    @param[in]  fd              Ignored\r
+    @param[in]  QueueSelector   Ignored\r
+\r
+    @retval -1    This function is not yet supported.  errno is set to ENOTSUP.\r
+**/\r
+int\r
+tcflush (\r
+  int fd,\r
+  int QueueSelector)\r
+{\r
+  errno = ENOTSUP;\r
+  return -1;\r
+}\r
+\r
index 5576938f8effe1c5f292a5cd1a4b87f88831aecf..c3b210120bd7a1c2a65cdcbc4b9ff99c0699bd77 100644 (file)
@@ -36,6 +36,7 @@
 #include  <unistd.h>\r
 #include  <kfile.h>\r
 #include  <Device/Device.h>\r
+#include  <Device/IIO.h>\r
 #include  <MainData.h>\r
 #include  <extern.h>\r
 \r
@@ -114,12 +115,14 @@ DeleteOnClose(int fd)
   return retval;\r
 }\r
 \r
-/** The isatty() function tests whether fildes, an open file descriptor,\r
+/** The isatty() function tests whether fd, an open file descriptor,\r
     is associated with a terminal device.\r
 \r
-    @retval   1   fildes is associated with a terminal.\r
-    @retval   0   fildes is not associated with a terminal.  errno is set to\r
-                  EBADF if fildes is not a valid open FD.\r
+    @param[in]  fd  File Descriptor for the file to be examined.\r
+\r
+    @retval   1   fd is associated with a terminal.\r
+    @retval   0   fd is not associated with a terminal.  errno is set to\r
+                  EBADF if fd is not a valid open FD.\r
 **/\r
 int\r
 isatty  (int fd)\r
@@ -129,7 +132,7 @@ isatty  (int fd)
 \r
   if(ValidateFD( fd, VALID_OPEN)) {\r
     Fp = &gMD->fdarray[fd];\r
-    retval =  Fp->f_iflags & _S_ITTY;\r
+    retval =  (Fp->f_iflags & _S_ITTY) ? 1 : 0;\r
   }\r
   else {\r
     errno = EBADF;\r
@@ -169,13 +172,14 @@ IsDupFd( int fd)
   return Ret;\r
 }\r
 \r
-/** Close a file and set its fd to the specified state.\r
+/** Worker function to Close a file and set its fd to the specified state.\r
 \r
     @param[in]    fd          The file descriptor to close.\r
     @param[in]    NewState    State to set the fd to after the file is closed.\r
 \r
     @retval    0    The operation completed successfully.\r
     @retval   -1    The operation failed.  Further information is in errno.\r
+                      * EBADF   fd is not a valid or open file descriptor.\r
 **/\r
 static int\r
 _closeX  (int fd, int NewState)\r
@@ -221,6 +225,8 @@ _closeX  (int fd, int NewState)
     descriptors. All outstanding record locks owned by the process on the file\r
     associated with the file descriptor are removed (that is, unlocked).\r
 \r
+    @param[in]    fd          Descriptor for the File to close.\r
+\r
     @retval   0     Successful completion.\r
     @retval   -1    An error occurred and errno is set to identify the error.\r
 **/\r
@@ -230,7 +236,14 @@ close  (int fd)
   return _closeX(fd, 0);\r
 }\r
 \r
-/**\r
+/** Delete the file specified by path.\r
+\r
+    @param[in]    path  The MBCS path of the file to delete.\r
+\r
+    @retval   -1  Unable to open the file specified by path.\r
+    @retval   -1  If (errno == EPERM), unlink is not permited for this file.\r
+    @retval   -1  Low-level delete filed.  Reason is in errno.\r
+    @retval   0   The file was successfully deleted.\r
 **/\r
 int\r
 unlink (const char *path)\r
@@ -315,6 +328,10 @@ unlink (const char *path)
                   descriptors greater than or equal to arg are available.\r
     [EOVERFLOW]   One of the values to be returned cannot be represented correctly.\r
 \r
+    @param[in]      fildes    Descriptor for the file to be controlled.\r
+    @param[in]      cmd       Command to be acted upon.\r
+    @param[in,out]  ...       Optional additional parameters as required by cmd.\r
+\r
     @return   Upon successful completion, the value returned shall depend on\r
               cmd as follows:\r
                 - F_DUPFD - A new file descriptor.\r
@@ -407,6 +424,8 @@ fcntl     (int fildes, int cmd, ...)
     shall be equivalent to:\r
       - fid = fcntl(fildes, F_DUPFD, 0);\r
 \r
+    @param[in]    fildes    Descriptor for the file to be examined.\r
+\r
     @return   Upon successful completion a non-negative integer, namely the\r
               file descriptor, shall be returned; otherwise, -1 shall be\r
               returned and errno set to indicate the error.\r
@@ -417,7 +436,9 @@ dup   (int fildes)
   return fcntl(fildes, F_DUPFD, 0);\r
 }\r
 \r
-/** The dup2() function provides an alternative interface to the\r
+/** Make fildes2 refer to a duplicate of fildes.\r
+\r
+    The dup2() function provides an alternative interface to the\r
     service provided by fcntl() using the F_DUPFD command. The call:\r
       - fid = dup2(fildes, fildes2);\r
     shall be equivalent to:\r
@@ -433,6 +454,9 @@ dup   (int fildes)
       - The value returned shall be equal to the value of fildes2 upon\r
         successful completion, or -1 upon failure.\r
 \r
+    @param[in]  fildes    File Descriptor to be duplicated.\r
+    @param[in]  fildes2   File Descriptor to be made a duplicate of fildes.\r
+\r
     @return   Upon successful completion a non-negative integer, namely\r
               fildes2, shall be returned; otherwise, -1 shall be\r
               returned and errno set to EBADF indicate the error.\r
@@ -470,13 +494,13 @@ dup2    (int fildes, int fildes2)
     fildes must be an open file descriptor.  lseek() repositions the file\r
     pointer fildes as follows:\r
 \r
-         If how is SEEK_SET, the offset is set to offset bytes.\r
+      - If how is SEEK_SET, the offset is set to offset bytes.\r
 \r
-         If how is SEEK_CUR, the offset is set to its current location\r
-         plus offset bytes.\r
+      - If how is SEEK_CUR, the offset is set to its current location\r
+        plus offset bytes.\r
 \r
-         If how is SEEK_END, the offset is set to the size of the file\r
-         plus offset bytes.\r
+      - If how is SEEK_END, the offset is set to the size of the file\r
+        plus offset bytes.\r
 \r
     The lseek() function allows the file offset to be set beyond the end of\r
     the existing end-of-file of the file.  If data is later written at this\r
@@ -486,6 +510,10 @@ dup2    (int fildes, int fildes2)
     Some devices are incapable of seeking.  The value of the pointer associ-\r
     ated with such a device is undefined.\r
 \r
+    @param[in]  fd        Descriptor for the File to be affected.\r
+    @param[in]  offset    Value to adjust the file position by.\r
+    @param[in]  how       How the file position is to be adjusted.\r
+\r
     @return   Upon successful completion, lseek() returns the resulting offset\r
               location as measured in bytes from the beginning of the file.\r
               Otherwise, a value of -1 is returned and errno is set to\r
@@ -524,6 +552,9 @@ lseek (int fd, __off_t offset, int how)
 \r
     The directory is closed after it is created.\r
 \r
+    @param[in]  path    The path to a directory to create.\r
+    @param[in]  perms   Permissions as defined in <sys/stat.h>\r
+\r
     @retval   0   The directory was created successfully.\r
     @retval  -1   An error occurred and error codes are stored in errno and EFIerrno.\r
 **/\r
@@ -606,19 +637,19 @@ mkdir (const char *path, __mode_t perms)
     @param[in]    oflags    File status flags and file access modes of the\r
                             open file description.\r
     @param[in]    mode      File access permission bits as defined in\r
-                            <sys/stat.h>.\r
+                            <sys/stat.h>.  Only used if a file is created\r
+                            as a result of the open.\r
 \r
     @return     Upon successful completion, open() opens the file and returns\r
                 a non-negative integer representing the lowest numbered\r
                 unused file descriptor. Otherwise, open returns -1 and sets\r
                 errno to indicate the error. If a negative value is\r
                 returned, no files are created or modified.\r
-\r
-    @retval   EMFILE      No file descriptors available -- Max number already open.\r
-    @retval   EINVAL      Bad value specified for oflags or mode.\r
-    @retval   ENOMEM      Failure allocating memory for internal buffers.\r
-    @retval   EEXIST      File exists and open attempted with (O_EXCL | O_CREAT) set.\r
-    @retval   EIO         UEFI failure.  Check value in EFIerrno.\r
+                  - EMFILE - No file descriptors available -- Max number already open.\r
+                  - EINVAL - Bad value specified for oflags or mode.\r
+                  - ENOMEM - Failure allocating memory for internal buffers.\r
+                  - EEXIST - File exists and open attempted with (O_EXCL | O_CREAT) set.\r
+                  - EIO - UEFI failure.  Check value in EFIerrno.\r
 **/\r
 int\r
 open(\r
@@ -631,18 +662,20 @@ open(
   wchar_t              *MPath;\r
   DeviceNode           *Node;\r
   struct __filedes     *filp;\r
+  struct termios       *Termio;\r
   int                   Instance  = 0;\r
   RETURN_STATUS         Status;\r
-  UINT64                OpenMode;\r
+  UINT32                OpenMode;\r
   int                   fd = -1;\r
   int                   doresult;\r
 \r
   Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath);\r
   if(Status == RETURN_SUCCESS) {\r
     if((Node == NULL)               ||\r
-       (Node->InstanceList == NULL)) {\r
+       (Node->InstanceList == NULL))\r
+    {\r
       errno   = EPERM;\r
-  }\r
+    }\r
     else {\r
   // Could add a test to see if the file name begins with a period.\r
   // If it does, then add the HIDDEN flag to Attributes.\r
@@ -666,23 +699,31 @@ open(
         fd = -1;              // Indicate an error\r
       }\r
       else {\r
-        // Re-use OpenMode in order to build our final f_iflags value\r
+        // Build our final f_iflags value\r
         OpenMode  = ( mode & S_ACC_READ )  ? S_ACC_READ : 0;\r
         OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;\r
 \r
-        filp->f_iflags |= (UINT32)OpenMode;\r
+        filp->f_iflags |= OpenMode;\r
+\r
+        if((oflags & O_TTY_INIT) && (filp->f_iflags & _S_ITTY) && (filp->devdata != NULL)) {\r
+          // Initialize the device's termios flags to a "sane" value\r
+          Termio = &((cIIO *)filp->devdata)->Termio;\r
+          Termio->c_iflag = ICRNL;\r
+          Termio->c_oflag = OPOST | ONLCR | OXTABS | ONOEOT | ONOCR | ONLRET | OCTRL;\r
+          Termio->c_lflag = ECHO | ECHOE | ECHONL | ICANON;\r
+          Termio->c_cc[VERASE]  = 0x08;   // ^H Backspace\r
+          Termio->c_cc[VKILL]   = 0x15;   // ^U\r
+          Termio->c_cc[VINTR]   = 0x03;   // ^C Interrupt character\r
+        }\r
         ++filp->RefCount;\r
         FILE_SET_MATURE(filp);\r
       }\r
           }\r
     }\r
-    if(NewPath != NULL) {\r
     free(NewPath);\r
         }\r
-  }\r
-  if(MPath != NULL) {\r
     free(MPath);    // We don't need this any more.\r
-  }\r
+\r
   // return the fd of our now open file\r
   return fd;\r
 }\r
@@ -699,11 +740,11 @@ open(
   <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">POSIX</a>\r
   documentation is available online.\r
 \r
-  @param [in] pfd       Address of an array of pollfd structures.\r
+  @param[in]  pfd       Address of an array of pollfd structures.\r
 \r
-  @param [in] nfds      Number of elements in the array of pollfd structures.\r
+  @param[in]  nfds      Number of elements in the array of pollfd structures.\r
 \r
-  @param [in] timeout   Length of time in milliseconds to wait for the event\r
+  @param[in]  timeout   Length of time in milliseconds to wait for the event\r
 \r
   @return     The number of file descriptors with detected events.  Zero\r
               indicates that the call timed out and -1 indicates an error.\r
@@ -841,38 +882,44 @@ poll (
 \r
 \r
 /** The rename() function changes the name of a file.\r
-    The old argument points to the pathname of the file to be renamed. The new\r
+    The From argument points to the pathname of the file to be renamed. The To\r
     argument points to the new pathname of the file.\r
 \r
-    If the old argument points to the pathname of a file that is not a\r
-    directory, the new argument shall not point to the pathname of a\r
-    directory. If the file named by the new argument exists, it shall be\r
-    removed and old renamed to new. Write access permission is required for\r
-    both the directory containing old and the directory containing new.\r
+    If the From argument points to the pathname of a file that is not a\r
+    directory, the To argument shall not point to the pathname of a\r
+    directory. If the file named by the To argument exists, it shall be\r
+    removed and From renamed to To. Write access permission is required for\r
+    both the directory containing old and the directory containing To.\r
 \r
-    If the old argument points to the pathname of a directory, the new\r
+    If the From argument points to the pathname of a directory, the To\r
     argument shall not point to the pathname of a file that is not a\r
-    directory. If the directory named by the new argument exists, it shall be\r
-    removed and old renamed to new.\r
+    directory. If the directory named by the To argument exists, it shall be\r
+    removed and From renamed to To.\r
 \r
-    The new pathname shall not contain a path prefix that names old. Write\r
-    access permission is required for the directory containing old and the\r
-    directory containing new. If the old argument points to the pathname of a\r
+    The To pathname shall not contain a path prefix that names From. Write\r
+    access permission is required for the directory containing From and the\r
+    directory containing To. If the From argument points to the pathname of a\r
     directory, write access permission may be required for the directory named\r
-    by old, and, if it exists, the directory named by new.\r
+    by From, and, if it exists, the directory named by To.\r
 \r
     If the rename() function fails for any reason other than [EIO], any file\r
-    named by new shall be unaffected.\r
+    named by To shall be unaffected.\r
 \r
-    @return   Upon successful completion, rename() shall return 0; otherwise,\r
-              -1 shall be returned, errno shall be set to indicate the error,\r
-              and neither the file named by old nor the file named by new\r
-              shall be changed or created.\r
+    @param[in]  From    Path to the file to be renamed.\r
+    @param[in]  To      The new name of From.\r
+\r
+    @retval   0     Successful completion.\r
+    @retval   -1    An error has occured and errno has been set to further specify the error.\r
+                    Neither the file named by From nor the file named by To are\r
+                    changed or created.\r
+                      - ENXIO: Path specified is not supported by any loaded driver.\r
+                      - ENOMEM: Insufficient memory to calloc a MapName buffer.\r
+                      - EINVAL: The path parameter is not valid.\r
 **/\r
 int\r
 rename(\r
-  const char *from,\r
-  const char *to\r
+  const char *From,\r
+  const char *To\r
   )\r
 {\r
   wchar_t            *FromPath;\r
@@ -882,7 +929,7 @@ rename(
   RETURN_STATUS       Status;\r
   int                 retval      = -1;\r
 \r
-  Status = ParsePath(from, &FromPath, &FromNode, &Instance, NULL);\r
+  Status = ParsePath(From, &FromPath, &FromNode, &Instance, NULL);\r
   if(Status == RETURN_SUCCESS) {\r
     GenI = FromNode->InstanceList;\r
     if(GenI == NULL) {\r
@@ -891,14 +938,19 @@ rename(
       }\r
       else {\r
       //GenI += (Instance * FromNode->InstanceSize);\r
-      retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( from, to);\r
+      retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( From, To);\r
               }\r
     free(FromPath);\r
             }\r
   return retval;\r
 }\r
 \r
-/**\r
+/** Delete a specified directory.\r
+\r
+    @param[in]  path    Path to the directory to delete.\r
+\r
+    @retval   -1    The directory couldn't be opened (doesn't exist).\r
+    @retval   -1    The directory wasn't empty or an IO error occured.\r
 **/\r
 int\r
 rmdir(\r
@@ -921,10 +973,10 @@ rmdir(
 }\r
 \r
 /** The fstat() function obtains information about an open file associated\r
-    with the file descriptor fildes, and shall write it to the area pointed to\r
-    by buf.\r
+    with the file descriptor fd, and writes it to the area pointed to\r
+    by statbuf.\r
 \r
-    The buf argument is a pointer to a stat structure, as defined\r
+    The statbuf argument is a pointer to a stat structure, as defined\r
     in <sys/stat.h>, into which information is placed concerning the file.\r
 \r
     The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime,\r
@@ -939,7 +991,7 @@ rmdir(
 \r
     The stat structure members which don't have direct analogs to EFI file\r
     information are filled in as follows:\r
-      - st_mode     Populated with information from fildes\r
+      - st_mode     Populated with information from fd\r
       - st_ino      Set to zero.  (inode)\r
       - st_dev      Set to zero.\r
       - st_uid      Set to zero.\r
@@ -974,6 +1026,9 @@ fstat (int fd, struct stat *statbuf)
     Opens the file pointed to by path, calls _EFI_FileInfo with the file's handle,\r
     then closes the file.\r
 \r
+    @param[in]    path      Path to the file to obtain information about.\r
+    @param[out]   statbuf   Buffer in which the file status is put.\r
+\r
     @retval    0  Successful Completion.\r
     @retval   -1  An error has occurred and errno has been set to\r
                   identify the error.\r
@@ -994,7 +1049,15 @@ stat   (const char *path, struct stat *statbuf)
   return retval;\r
 }\r
 \r
-/**  Same as stat since EFI doesn't have symbolic links.  **/\r
+/**  Same as stat since EFI doesn't have symbolic links.\r
+\r
+    @param[in]    path      Path to the file to obtain information about.\r
+    @param[out]   statbuf   Buffer in which the file status is put.\r
+\r
+    @retval    0  Successful Completion.\r
+    @retval   -1  An error has occurred and errno has been set to\r
+                  identify the error.\r
+**/\r
 int\r
 lstat (const char *path, struct stat *statbuf)\r
 {\r
@@ -1002,6 +1065,13 @@ lstat (const char *path, struct stat *statbuf)
 }\r
 \r
 /** Control a device.\r
+\r
+    @param[in]        fd        Descriptor for the file to be acted upon.\r
+    @param[in]        request   Specifies the operation to perform.\r
+    @param[in,out]    ...       Zero or more parameters as required for request.\r
+\r
+    @retval   >=0   The operation completed successfully.\r
+    @retval   -1    An error occured.  More information is in errno.\r
 **/\r
 int\r
 ioctl(\r
@@ -1098,6 +1168,10 @@ ioctl(
     directory entries, the read returns a zero-length buffer.\r
     EFI_FILE_INFO is the structure returned as the directory entry.\r
 \r
+    @param[in]    fildes  Descriptor of the file to be read.\r
+    @param[out]   buf     Pointer to location in which to store the read data.\r
+    @param[in]    nbyte   Maximum number of bytes to be read.\r
+\r
     @return   Upon successful completion, read() returns a non-negative integer\r
               indicating the number of bytes actually read. Otherwise, the\r
               functions return a negative value and sets errno to indicate the\r
@@ -1109,62 +1183,91 @@ ssize_t
 read   (int fildes, void *buf, size_t nbyte)\r
 {\r
   struct __filedes *filp;\r
+  cIIO             *IIO;\r
   ssize_t           BufSize;\r
 \r
   BufSize = (ssize_t)nbyte;\r
-  if(ValidateFD( fildes, VALID_OPEN)) {\r
-    filp = &gMD->fdarray[fildes];\r
+  if(BufSize > 0) {\r
+    if(ValidateFD( fildes, VALID_OPEN)) {\r
+      filp = &gMD->fdarray[fildes];\r
 \r
-    BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);\r
-  }\r
-  else {\r
-    errno = EBADF;\r
-    BufSize = -EBADF;\r
+      IIO = filp->devdata;\r
+      if(isatty(fildes) && (IIO != NULL)) {\r
+        BufSize = IIO->Read(filp, nbyte, buf);\r
+      }\r
+      else {\r
+        BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);\r
+      }\r
+    }\r
+    else {\r
+      errno = EBADF;\r
+      BufSize = -1;\r
+    }\r
   }\r
   return BufSize;\r
 }\r
 \r
 /** Write data to a file.\r
 \r
-  This function writes the specified number of bytes to the file at the current\r
-  file position. The current file position is advanced the actual number of bytes\r
-  written, which is returned in BufferSize. Partial writes only occur when there\r
-  has been a data error during the write attempt (such as "volume space full").\r
-  The file is automatically grown to hold the data if required. Direct writes to\r
-  opened directories are not supported.\r
-\r
-  If fildes refers to a terminal device, isatty() returns TRUE, a partial write\r
-  will occur if a NULL or EOF character is encountered before n characters have\r
-  been written.  Characters inserted due to line-end translations will not be\r
-  counted.  Unconvertable characters are translated into the UEFI character\r
-  BLOCKELEMENT_LIGHT_SHADE.\r
-\r
-  Since the UEFI console device works on wide characters, the buffer is assumed\r
-  to contain a single-byte character stream which is then translated to wide\r
-  characters using the btowc() functions.  The resulting wide character stream\r
-  is what is actually sent to the UEFI console.\r
-\r
-  QUESTION:  Should writes to stdout or stderr always succeed?\r
+    This function writes the specified number of bytes to the file at the current\r
+    file position. The current file position is advanced the actual number of bytes\r
+    written, which is returned in BufferSize. Partial writes only occur when there\r
+    has been a data error during the write attempt (such as "volume space full").\r
+    The file is automatically grown to hold the data if required. Direct writes to\r
+    opened directories are not supported.\r
+\r
+    If fildes refers to a terminal device, isatty() returns TRUE, a partial write\r
+    will occur if a NULL or EOF character is encountered before n characters have\r
+    been written.  Characters inserted due to line-end translations will not be\r
+    counted.  Unconvertable characters are translated into the UEFI character\r
+    BLOCKELEMENT_LIGHT_SHADE.\r
+\r
+    Since the UEFI console device works on wide characters, the buffer is assumed\r
+    to contain a single-byte character stream which is then translated to wide\r
+    characters using the mbtowc() functions.  The resulting wide character stream\r
+    is what is actually sent to the UEFI console.\r
+\r
+    @param[in]  fd      Descriptor of file to be written to.\r
+    @param[in]  buf     Pointer to data to write to the file.\r
+    @param[in]  nbyte   Number of bytes to be written to the file.\r
+\r
+    @retval   >=0   Number of bytes actually written to the file.\r
+    @retval   <0    An error occurred.  More data is provided by errno.\r
 **/\r
 ssize_t\r
 write  (int fd, const void *buf, size_t nbyte)\r
 {\r
   struct __filedes *filp;\r
+  cIIO             *IIO;\r
   ssize_t           BufSize;\r
-//  EFI_FILE_HANDLE   FileHandle;\r
-//  RETURN_STATUS     Status = RETURN_SUCCESS;\r
 \r
   BufSize = (ssize_t)nbyte;\r
 \r
   if(ValidateFD( fd, VALID_OPEN)) {\r
     filp = &gMD->fdarray[fd];\r
-\r
-    BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);\r
+    if ((filp->Oflags & O_ACCMODE) != 0) {\r
+      // File is open for writing\r
+      IIO = filp->devdata;\r
+      if(isatty(fd) && (IIO != NULL)) {\r
+        // Output to an Interactive I/O device\r
+        BufSize = IIO->Write(filp, buf, nbyte);\r
+      }\r
+      else {\r
+        // Output to a file, socket, pipe, etc.\r
+        BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);\r
+      }\r
     }\r
     else {\r
+      // File is NOT open for writing\r
+      errno = EINVAL;\r
+      BufSize = -1;\r
+    }\r
+  }\r
+  else {\r
+    // fd is not for a valid open file\r
     errno = EBADF;\r
-    BufSize = -EBADF;\r
-      }\r
+    BufSize = -1;\r
+  }\r
   return BufSize;\r
 }\r
 \r
@@ -1260,11 +1363,29 @@ chdir (const char *path)
   return -1;\r
 }\r
 \r
+/** Get the foreground process group ID associated with a terminal.\r
+\r
+    Just returns the Image Handle for the requestor since UEFI does not have\r
+    a concept of processes or groups.\r
+\r
+    @param[in]    x   Ignored.\r
+\r
+    @return   Returns the Image Handle of the application or driver which\r
+              called this function.\r
+**/\r
 pid_t tcgetpgrp (int x)\r
 {\r
   return ((pid_t)(UINTN)(gImageHandle));\r
 }\r
 \r
+/** Get the process group ID of the calling process.\r
+\r
+    Just returns the Image Handle for the requestor since UEFI does not have\r
+    a concept of processes or groups.\r
+\r
+    @return   Returns the Image Handle of the application or driver which\r
+              called this function.\r
+**/\r
 pid_t getpgrp(void)\r
 {\r
   return ((pid_t)(UINTN)(gImageHandle));\r
@@ -1300,10 +1421,11 @@ va_Utimes(
 \r
 /** Set file access and modification times.\r
 \r
-    @param[in]  path\r
-    @param[in]  times\r
+    @param[in]  path    Path to the file to be modified.\r
+    @param[in]  times   Pointer to an array of two timeval structures\r
 \r
-    @return\r
+    @retval   0     File times successfully set.\r
+    @retval   -1    An error occured.  Error type in errno.\r
 **/\r
 int\r
 utimes(\r
@@ -1313,4 +1435,3 @@ utimes(
 {\r
   return va_Utimes(path, times);\r
 }\r
-\r
index c352b22455695adef3e71a424965600fab9896a2..f9f28b872bd9e0a4decf9a9d4e69f40ea6cdae22 100644 (file)
   StdLib/LibC/Uefi/Devices/daConsole.inf\r
   StdLib/LibC/Uefi/Devices/daShell.inf\r
 \r
+# Additional, non-standard, libraries\r
+  StdLib/LibC/Containers/ContainerLib.inf\r
+\r
 # Additional libraries for POSIX functionality.\r
   StdLib/PosixLib/Err/LibErr.inf\r
   StdLib/PosixLib/Gen/LibGen.inf\r
   StdLib/PosixLib/Glob/LibGlob.inf\r
   StdLib/PosixLib/Stringlist/LibStringlist.inf\r
+  StdLib/LibC/Uefi/InteractiveIO/IIO.inf\r
 \r
 #    Socket Libraries - LibC based\r
   StdLib/BsdSocketLib/BsdSocketLib.inf\r
index 4b7e37eb65e95800480cae2939bf9f1344b0c67a..9b014b9fc6bca3fb6f3a7ff7a926a58d444ddb0f 100644 (file)
   LibGen|StdLib/PosixLib/Gen/LibGen.inf\r
   LibGlob|StdLib/PosixLib/Glob/LibGlob.inf\r
   LibStringlist|StdLib/PosixLib/Stringlist/LibStringlist.inf\r
+  LibIIO|StdLib/LibC/Uefi/InteractiveIO/IIO.inf\r
+\r
+# Additional, non-standard, libraries\r
+  LibContainer|StdLib/LibC/Containers/ContainerLib.inf\r
 \r
 # Libraries for device abstractions within the Standard C Library\r
 # Applications should not directly access any functions defined in these libraries.\r