1 /** @file
2   Utilities for Interactive I/O Functions.
3 
4   The functions assume that isatty() is TRUE at the time they are called.
5 
6   Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
7   This program and the accompanying materials are licensed and made available
8   under the terms and conditions of the BSD License which accompanies this
9   distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php.
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 **/
15 #include  <Uefi.h>
16 #include  <Protocol/SimpleTextOut.h>
17 
18 #include  <LibConfig.h>
19 
20 #include  <assert.h>
21 #include  <errno.h>
22 #include  <sys/syslimits.h>
23 #include  <sys/termios.h>
24 #include  <Device/IIO.h>
25 #include  <MainData.h>
26 #include  "IIOutilities.h"
27 
28 /** Get the low-level UEFI protocol associated with an open file.
29 
30     @param[in]    fd    File descriptor for an open file.
31     @param[out]   filp  NULL, or a pointer to where a pointer to the file's
32                         file descriptor structure is to be stored.
33 
34     @return   Returns NULL if fd is not a valid file descriptor, otherwise
35               a pointer to the file's associated UEFI protocol is returned.
36 **/
37 void *
38 EFIAPI
IIO_GetDeviceProto(int fd,struct __filedes ** filp)39 IIO_GetDeviceProto (
40   int                 fd,
41   struct __filedes  **filp
42   )
43 {
44   void               *Proto;
45   ConInstance        *Stream;
46   struct __filedes   *pfil;
47 
48   Proto = NULL;
49   if(ValidateFD( fd, VALID_OPEN)) {
50     pfil = &gMD->fdarray[fd];
51     Stream = BASE_CR(pfil->f_ops, ConInstance, Abstraction);
52     Proto = (void *)Stream->Dev;
53     if(filp != NULL) {
54       *filp = pfil;
55     }
56   }
57   return Proto;
58 }
59 
60 /** Get a character either from the input buffer or from hardware.
61 
62     @param[in]    filp      Pointer to a file descriptor structure.
63     @param[in]    First     Set to TRUE to identify the initial read.
64 
65     @return   Returns a character read from either the input buffer
66               or from the open file (device) identified by filp.
67               A return value of WEOF indicates an error has occurred.
68 **/
69 wint_t
70 EFIAPI
IIO_GetInChar(struct __filedes * filp,BOOLEAN First)71 IIO_GetInChar (
72   struct __filedes *filp,
73   BOOLEAN           First
74 )
75 {
76   cIIO             *This;
77   cFIFO            *InBuf;
78   size_t            Status;
79   ssize_t           NumRead;
80   wint_t            RetVal;
81   wchar_t           InChar;
82 
83   static size_t     BufCnt;
84 
85   This      = filp->devdata;
86   InBuf     = This->InBuf;
87 
88   NumRead = -1;
89   InChar  =  0;
90   if(First) {
91     BufCnt = InBuf->Count(InBuf, AsElements);
92   }
93   if(BufCnt > 0) {
94     Status = InBuf->Read(InBuf, &InChar, 1);
95     if (Status > 0) {
96       --BufCnt;
97       NumRead = 1;
98     }
99   }
100   else {
101     NumRead = filp->f_ops->fo_read(filp, &filp->f_offset, sizeof(wchar_t), &InChar);
102   }
103   if(NumRead <= 0) {
104     RetVal = WEOF;
105   }
106   else {
107     RetVal = (wint_t)InChar;
108   }
109   return RetVal;
110 }
111 
112 /** Get the current cursor position.
113 
114     @param[in]      fd      File descriptor for an open file.
115     @param[out]     Column  Pointer to where the current cursor column is to be stored.
116     @param[out]     Row     Pointer to where the current cursor row is to be stored.
117 
118     @retval   -1    fd is not an IIO output device.
119     @retval    0    Cursor position retrieved, Cursor is Not Visible.
120     @retval    1    Cursor position retrieved, Cursor is Visible.
121 **/
122 int
123 EFIAPI
IIO_GetCursorPosition(int fd,UINT32 * Column,UINT32 * Row)124 IIO_GetCursorPosition (
125   int       fd,
126   UINT32   *Column,
127   UINT32   *Row
128   )
129 {
130   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;
131   struct __filedes                   *pStdOut;
132   int                                 RetVal;
133 
134   RetVal    = -1;
135 
136   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(fd, &pStdOut);
137   if(Proto != NULL) {
138     if(((pStdOut->f_iflags & _S_ITTY) != 0) &&    // file is a TTY
139        ((pStdOut->Oflags & O_ACCMODE) != 0))      // and it is open for output
140     {
141       // fd is for a TTY or "Interactive IO" device
142       *Column  = Proto->Mode->CursorColumn;
143       *Row     = Proto->Mode->CursorRow;
144       if(Proto->Mode->CursorVisible) {
145         RetVal = 1;
146       }
147       else {
148         RetVal = 0;
149       }
150     }
151   }
152   return RetVal;
153 }
154 
155 /** Set the cursor position.
156 
157     @param[in]    filp    Pointer to the output device's file descriptor structure.
158     @param[in]    StartXY Pointer to a cursor coordinate (XY) structure indicating
159                           the desired coordinate to move the cursor to.
160 
161     @retval   -1    fd is not an IIO output device
162     @retval    0    Cursor position set successfully.
163 **/
164 int
165 EFIAPI
IIO_SetCursorPosition(struct __filedes * filp,CURSOR_XY * CursorXY)166 IIO_SetCursorPosition (
167   struct __filedes *filp,
168   CURSOR_XY        *CursorXY
169   )
170 {
171   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;
172   cIIO                               *This;
173   EFI_STATUS                          Status;
174   int                                 RetVal;
175 
176   RetVal    = -1;
177 
178   This = filp->devdata;
179   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(filp->MyFD, NULL);
180   if(Proto != NULL) {
181     if(((filp->f_iflags & _S_ITTY) != 0) &&    // file is a TTY
182        ((filp->Oflags & O_ACCMODE) != 0))      // and it is open for output
183     {
184       // fd is for a TTY or "Interactive IO" device
185       Status = Proto->SetCursorPosition(Proto, CursorXY->Column, CursorXY->Row);
186       if(Status == EFI_SUCCESS) {
187         This->CurrentXY.Column  = CursorXY->Column;
188         This->CurrentXY.Row     = CursorXY->Row;
189         RetVal = 0;
190       }
191     }
192   }
193   return RetVal;
194 }
195 
196 /** Get Output screen size and mode.
197 
198     @param[in]    fd    File descriptor of the output device.
199     @param[out]   Col   Pointer to where to store the MAX Column, or NULL.
200     @param[out]   Row   Pointer to where to store the MAX Row, or NULL.
201 
202     @retval   <0    An error occurred.  The reason is in errno and EFIerrno.
203                       * EIO     UEFI QueryMode failed
204                       * ENOTTY  fd does not refer to an interactive output device
205     @retval   >=0   Current output mode
206 **/
207 int
208 EFIAPI
IIO_GetOutputSize(int fd,UINTN * Col,UINTN * Row)209 IIO_GetOutputSize (
210   int       fd,
211   UINTN    *Col,
212   UINTN    *Row
213 )
214 {
215   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;
216   struct __filedes                   *pStdOut;
217   EFI_STATUS                          Status;
218   UINTN                               TempCol;
219   UINTN                               TempRow;
220   UINTN                               TempMode;
221   int                                 RetVal;
222 
223   RetVal    = -1;
224 
225   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(fd, &pStdOut);
226   if(Proto != NULL) {
227     if(((pStdOut->f_iflags & _S_ITTY) != 0)   &&    // file is a TTY
228         ((pStdOut->Oflags & O_ACCMODE) != 0))       // and it is open for output
229     {
230       // fd is for a TTY or "Interactive IO" device
231       TempMode = Proto->Mode->Mode;
232       Status = Proto->QueryMode(Proto, TempMode, &TempCol, &TempRow);
233       if(EFI_ERROR(Status)) {
234         EFIerrno  = Status;
235         errno     = EIO;
236       }
237       else {
238         *Col    = TempCol;
239         *Row    = TempRow;
240         RetVal  = (int)TempMode;
241       }
242     }
243     else {
244       errno = ENOTTY;
245     }
246   }
247   return RetVal;
248 }
249 
250 /** Calculate the number of character positions between two X/Y coordinate pairs.
251 
252     Using the current output device characteristics, calculate the number of
253     characters between two coordinates.  It is assumed that EndXY points to
254     an output location that occurs after StartXY.
255 
256     RowDelta is the computed difference between the ending and starting rows.
257     If RowDelta < 0, then EndXY is NOT after StartXY, so assert.
258 
259     ColumnDelta is the computed number of character positions (columns) between
260     the starting position and the ending position.  If ColumnDelta is < 0,
261     then EndXY is NOT after StartXY, so assert.
262 
263     @param[in]      This      Pointer to the IIO instance to be examined.
264     @param[in]      StartXY   Pointer to the starting coordinate pair.
265     @param[in]      EndXY     Pointer to the ending coordinate pair.
266 
267     @return   Returns the difference between the starting and ending coordinates.
268               The return value is positive if the coordinates contained in EndXY
269               are larger than StartXY, otherwise the return value is negative.
270 **/
271 int
272 EFIAPI
IIO_CursorDelta(cIIO * This,CURSOR_XY * StartXY,CURSOR_XY * EndXY)273 IIO_CursorDelta (
274   cIIO         *This,
275   CURSOR_XY    *StartXY,
276   CURSOR_XY    *EndXY
277 )
278 {
279   int    ColumnDelta;
280   int    RowDelta;
281 
282   RowDelta = (int)EndXY->Row - (int)StartXY->Row;
283 
284   assert(RowDelta >= 0);    // assert if EndXY is NOT after StartXY
285 
286   ColumnDelta = (int)((This->MaxColumn * RowDelta) + EndXY->Column);
287   ColumnDelta -= (int)StartXY->Column;
288 
289   return ColumnDelta;
290 }
291