EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

StdLib/LibC/Uefi/Devices/Console/daConsole.c

Go to the documentation of this file.
00001 
00016 #include  <Uefi.h>
00017 #include  <Library/BaseLib.h>
00018 #include  <Library/MemoryAllocationLib.h>
00019 #include  <Library/UefiBootServicesTableLib.h>
00020 #include  <Protocol/SimpleTextIn.h>
00021 #include  <Protocol/SimpleTextOut.h>
00022 
00023 #include  <LibConfig.h>
00024 #include  <sys/EfiSysCall.h>
00025 
00026 #include  <errno.h>
00027 #include  <wctype.h>
00028 #include  <wchar.h>
00029 #include  <stdarg.h>
00030 #include  <sys/fcntl.h>
00031 #include  <kfile.h>
00032 #include  <Device/Device.h>
00033 #include  <MainData.h>
00034 
00035 static const CHAR16* const
00036 stdioNames[NUM_SPECIAL]   = {
00037   L"stdin:", L"stdout:", L"stderr:"
00038 };
00039 
00040 static const int stdioFlags[NUM_SPECIAL] = {
00041   O_RDONLY,             // stdin
00042   O_WRONLY,             // stdout
00043   O_WRONLY              // stderr
00044 };
00045 
00046 static DeviceNode    *ConNode[NUM_SPECIAL];
00047 static ConInstance   *ConInstanceList;
00048 
00049 static wchar_t       *ConReadBuf;
00050 
00051 /* Flags settable by Ioctl */
00052 static BOOLEAN        TtyCooked;
00053 static BOOLEAN        TtyEcho;
00054 
00055 ssize_t
00056 WideTtyCvt( CHAR16 *dest, const char *buf, size_t n)
00057 {
00058   UINTN   i;
00059   wint_t  wc;
00060 
00061   for(i = 0; i < n; ++i) {
00062     wc = btowc(*buf++);
00063     if( wc == 0) {
00064       break;
00065     };
00066     if(wc < 0) {
00067       wc = BLOCKELEMENT_LIGHT_SHADE;
00068     }
00069     if(wc == L'\n') {
00070       *dest++ = L'\r';
00071     }
00072     *dest++ = (CHAR16)wc;
00073   }
00074   *dest = 0;
00075   return (ssize_t)i;
00076 }
00077 
00078 static
00079 int
00080 EFIAPI
00081 da_ConClose(
00082   IN      struct __filedes   *filp
00083 )
00084 {
00085   ConInstance    *Stream;
00086 
00087   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
00088   // Quick check to see if Stream looks reasonable
00089   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
00090     EFIerrno = RETURN_INVALID_PARAMETER;
00091     return -1;    // Looks like a bad File Descriptor pointer
00092   }
00093   gMD->StdIo[Stream->InstanceNum] = NULL;   // Mark the stream as closed
00094   return RETURN_SUCCESS;
00095 }
00096 
00097 static
00098 off_t
00099 EFIAPI
00100 da_ConSeek(
00101   struct __filedes   *filp,
00102   off_t               Position,
00103   int                 whence      
00104 )
00105 {
00106   ConInstance                       *Stream;
00107   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *Proto;
00108   XYoffset                           CursorPos;
00109 
00110   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
00111   // Quick check to see if Stream looks reasonable
00112   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
00113     EFIerrno = RETURN_INVALID_PARAMETER;
00114     return -1;    // Looks like a bad This pointer
00115   }
00116   if(Stream->InstanceNum == STDIN_FILENO) {
00117     // Seek is not valid for stdin
00118     EFIerrno = RETURN_UNSUPPORTED;
00119     return -1;
00120   }
00121   // Everything is OK to do the final verification and "seek".
00122   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
00123   CursorPos.Offset = Position;
00124 
00125   EFIerrno = Proto->SetCursorPosition(Proto,
00126                                       (INTN)CursorPos.XYpos.Column,
00127                                       (INTN)CursorPos.XYpos.Row);
00128 
00129   if(RETURN_ERROR(EFIerrno)) {
00130     return -1;
00131   }
00132   else {
00133     return Position;
00134   }
00135 }
00136 
00137 /* Write a NULL terminated WCS to the EFI console.
00138 
00139   @param[in,out]  BufferSize  Number of bytes in Buffer.  Set to zero if
00140                               the string couldn't be displayed.
00141   @param[in]      Buffer      The WCS string to be displayed
00142 
00143   @return   The number of characters written.
00144 */
00145 static
00146 ssize_t
00147 EFIAPI
00148 da_ConWrite(
00149   IN  struct __filedes     *filp,
00150   IN  off_t                *Position,
00151   IN  size_t                BufferSize,
00152   IN  const void           *Buffer
00153   )
00154 {
00155   EFI_STATUS                          Status;
00156   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;
00157   ConInstance                        *Stream;
00158   ssize_t                             NumChar;
00159   //XYoffset                            CursorPos;
00160 
00161   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
00162   // Quick check to see if Stream looks reasonable
00163   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
00164     EFIerrno = RETURN_INVALID_PARAMETER;
00165     return -1;    // Looks like a bad This pointer
00166   }
00167   if(Stream->InstanceNum == STDIN_FILENO) {
00168     // Write is not valid for stdin
00169     EFIerrno = RETURN_UNSUPPORTED;
00170     return -1;
00171   }
00172   // Everything is OK to do the write.
00173   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
00174 
00175   // Convert string from MBCS to WCS and translate \n to \r\n.
00176   NumChar = WideTtyCvt(gMD->UString, (const char *)Buffer, BufferSize);
00177   //if(NumChar > 0) {
00178   //  BufferSize = (size_t)(NumChar * sizeof(CHAR16));
00179   //}
00180   BufferSize = NumChar;
00181 
00182   //if( Position != NULL) {
00183   //  CursorPos.Offset = (UINT64)*Position;
00184 
00185   //  Status = Proto->SetCursorPosition(Proto,
00186   //                                    (INTN)CursorPos.XYpos.Column,
00187   //                                    (INTN)CursorPos.XYpos.Row);
00188   //  if(RETURN_ERROR(Status)) {
00189   //    return -1;
00190   //  }
00191   //}
00192 
00193   // Send the Unicode buffer to the console
00194   Status = Proto->OutputString( Proto, gMD->UString);
00195   // Depending on status, update BufferSize and return
00196   if(RETURN_ERROR(Status)) {
00197     BufferSize = 0;    // We don't really know how many characters made it out
00198   }
00199   else {
00200     //BufferSize = NumChar;
00201     Stream->NumWritten += NumChar;
00202   }
00203   EFIerrno = Status;
00204   return BufferSize;
00205 }
00206 
00218 static
00219 ssize_t
00220 EFIAPI
00221 da_ConRead(
00222   IN OUT  struct __filedes   *filp,
00223   IN OUT  off_t              *offset,         // Console ignores this
00224   IN      size_t              BufferSize,
00225      OUT  VOID               *Buffer
00226 )
00227 {
00228   EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *Proto;
00229   ConInstance                      *Stream;
00230   wchar_t                          *OutPtr;
00231   EFI_INPUT_KEY                     Key;
00232   UINTN                             NumChar;
00233   UINTN                             Edex;
00234   EFI_STATUS                        Status = RETURN_SUCCESS;
00235   UINTN                             i;
00236   char                              EchoBuff[MB_CUR_MAX + 1];
00237   int                               NumEcho;
00238 
00239   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
00240   // Quick check to see if Stream looks reasonable
00241   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
00242     EFIerrno = RETURN_INVALID_PARAMETER;
00243     return -1;    // Looks like a bad This pointer
00244   }
00245   if(Stream->InstanceNum != STDIN_FILENO) {
00246     // Read only valid for stdin
00247     EFIerrno = RETURN_UNSUPPORTED;
00248     return -1;
00249   }
00250   // It looks like things are OK for trying to read
00251   // We will accumulate *BufferSize characters or until we encounter
00252   // an "activation" character.  Currently any control character.
00253   Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
00254   OutPtr = ConReadBuf;
00255   NumChar = (BufferSize > MAX_INPUT)? MAX_INPUT : BufferSize;
00256   i = 0;
00257   do {
00258     if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {
00259       Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);
00260       if(Status != RETURN_SUCCESS) {
00261         break;
00262       }
00263       Status = Proto->ReadKeyStroke(Proto, &Key);
00264       if(Status != RETURN_SUCCESS) {
00265         break;
00266       }
00267     }
00268     else {
00269       Key.ScanCode          = Stream->UnGetKey.ScanCode;
00270       Key.UnicodeChar       = Stream->UnGetKey.UnicodeChar;
00271       Stream->UnGetKey.ScanCode     = SCAN_NULL;
00272       Stream->UnGetKey.UnicodeChar  = CHAR_NULL;
00273     }
00274     if(Key.ScanCode == SCAN_NULL) {
00275       NumEcho = 0;
00276       if(TtyCooked && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
00277         *OutPtr++ = CHAR_LINEFEED;
00278         NumEcho = wctomb(EchoBuff, CHAR_LINEFEED);
00279       }
00280       else {
00281         *OutPtr++ = Key.UnicodeChar;
00282         NumEcho = wctomb(EchoBuff, Key.UnicodeChar);
00283       }
00284       ++i;
00285       EchoBuff[NumEcho] = 0;  /* Terminate the Echo buffer */
00286       if(TtyEcho) {
00287         /* Echo the character just input */
00288         da_ConWrite(&gMD->fdarray[STDOUT_FILENO], NULL, 2, EchoBuff);
00289       }
00290     }
00291     if(iswcntrl(Key.UnicodeChar)) {    // If a control character, or a scan code
00292       break;
00293     }
00294   } while(i < NumChar);
00295 
00296   *OutPtr = L'\0';    // Terminate the input buffer
00297 
00298   /*  Convert the input buffer and place in Buffer.
00299       If the fully converted input buffer won't fit, write what will and
00300       leave the rest in ConReadBuf with ConReadLeft indicating how many
00301       unconverted characters remain in ConReadBuf.
00302   */
00303   NumEcho = (int)wcstombs(Buffer, ConReadBuf, BufferSize);   /* Re-use NumEcho to hold number of bytes in Buffer */
00304   /* More work needs to be done before locales other than C can be supported. */
00305 
00306   EFIerrno = Status;
00307   return (ssize_t)NumEcho;  // Will be 0 if we didn't get a key
00308 }
00309 
00319 static
00320 int
00321 EFIAPI
00322 da_ConStat(
00323   struct __filedes   *filp,
00324   struct stat        *Buffer,
00325   void               *Something
00326   )
00327 {
00328   ConInstance                        *Stream;
00329   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;
00330   XYoffset                            CursorPos;
00331   INT32                               OutMode;
00332   UINTN                               ModeCol;
00333   UINTN                               ModeRow;
00334 
00335 // ConGetInfo
00336   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
00337   // Quick check to see if Stream looks reasonable
00338   if ((Stream->Cookie != CON_COOKIE) ||    // Cookie == 'IoAb'
00339       (Buffer == NULL))
00340   {
00341     EFIerrno = RETURN_INVALID_PARAMETER;
00342     return -1;
00343   }
00344   // All of our parameters are correct, so fill in the information.
00345   Buffer->st_blksize = 1;
00346 
00347 // ConGetPosition
00348   if(Stream->InstanceNum == STDIN_FILENO) {
00349     // This is stdin
00350     Buffer->st_curpos    = 0;
00351     Buffer->st_size      = (off_t)Stream->NumRead;
00352     Buffer->st_physsize  = 1;
00353   }
00354   else {
00355     Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
00356     CursorPos.XYpos.Column  = (UINT32)Proto->Mode->CursorColumn;
00357     CursorPos.XYpos.Row     = (UINT32)Proto->Mode->CursorRow;
00358     Buffer->st_curpos       = (off_t)CursorPos.Offset;
00359     Buffer->st_size         = (off_t)Stream->NumWritten;
00360 
00361     OutMode  = Proto->Mode->Mode;
00362     EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow);
00363     if(RETURN_ERROR(EFIerrno)) {
00364       Buffer->st_physsize = 0;
00365     }
00366     else {
00367       CursorPos.XYpos.Column  = (UINT32)ModeCol;
00368       CursorPos.XYpos.Row     = (UINT32)ModeRow;
00369       Buffer->st_physsize     = (off_t)CursorPos.Offset;
00370     }
00371   }
00372   return 0;
00373 }
00374 
00375 static
00376 int
00377 EFIAPI
00378 da_ConIoctl(
00379   struct __filedes   *filp,
00380   ULONGN              cmd,
00381   va_list             argp
00382   )
00383 {
00384   return -EPERM;
00385 }
00386 
00389 int
00390 EFIAPI
00391 da_ConOpen(
00392   DeviceNode         *DevNode,
00393   struct __filedes   *filp,
00394   int                 DevInstance,    // Not used for console devices
00395   wchar_t            *Path,           // Not used for console devices
00396   wchar_t            *MPath           // Not used for console devices
00397   )
00398 {
00399   ConInstance                      *Stream;
00400 
00401   if((filp == NULL)           ||
00402      (DevNode  == NULL))
00403   {
00404     EFIerrno = RETURN_INVALID_PARAMETER;
00405     errno = EINVAL;
00406     return -1;
00407   }
00408   Stream = (ConInstance *)DevNode->InstanceList;
00409   // Quick check to see if Stream looks reasonable
00410   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
00411     EFIerrno = RETURN_INVALID_PARAMETER;
00412     errno = EINVAL;
00413     return -1;    // Looks like a bad This pointer
00414   }
00415   gMD->StdIo[Stream->InstanceNum] = Stream;
00416   filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE);
00417   filp->f_offset = 0;
00418   filp->f_ops = &Stream->Abstraction;
00419 
00420   return 0;
00421 }
00422 
00423 #include  <sys/poll.h>
00424 /*  Returns a bit mask describing which operations could be completed immediately.
00425 
00426     (POLLIN | POLLRDNORM)   A Unicode character is available to read
00427     (POLLIN)                A ScanCode is ready.
00428     (POLLOUT)               The device is ready for output - always set on stdout and stderr.
00429 
00430 */
00431 static
00432 short
00433 EFIAPI
00434 da_ConPoll(
00435   struct __filedes   *filp,
00436   short              events
00437   )
00438 {
00439   EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *Proto;
00440   ConInstance                      *Stream;
00441   EFI_STATUS                        Status = RETURN_SUCCESS;
00442   short                             RdyMask = 0;
00443 
00444   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
00445   // Quick check to see if Stream looks reasonable
00446   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
00447     EFIerrno = RETURN_INVALID_PARAMETER;
00448     return POLLNVAL;    // Looks like a bad filp pointer
00449   }
00450   if(Stream->InstanceNum == 0) {
00451     // Only input is supported for this device
00452     Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
00453     if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {
00454       Status = Proto->ReadKeyStroke(Proto, &Stream->UnGetKey);
00455       if(Status == RETURN_SUCCESS) {
00456         RdyMask = POLLIN;
00457         if(Stream->UnGetKey.UnicodeChar != CHAR_NULL) {
00458           RdyMask |= POLLRDNORM;
00459         }
00460       }
00461       else {
00462         Stream->UnGetKey.ScanCode     = SCAN_NULL;
00463         Stream->UnGetKey.UnicodeChar  = CHAR_NULL;
00464       }
00465     }
00466   }
00467   else if(Stream->InstanceNum < NUM_SPECIAL) {  // Not 0, is it 1 or 2?
00468     // Only output is supported for this device
00469     RdyMask = POLLOUT;
00470   }
00471   else {
00472     RdyMask = POLLERR;    // Not one of the standard streams
00473   }
00474   EFIerrno = Status;
00475 
00476   return (RdyMask & (events | POLL_RETONLY));
00477 }
00478 
00484 RETURN_STATUS
00485 EFIAPI
00486 __Cons_construct(
00487   IN EFI_HANDLE        ImageHandle,
00488   IN EFI_SYSTEM_TABLE  *SystemTable
00489 )
00490 {
00491   ConInstance    *Stream;
00492   RETURN_STATUS   Status = RETURN_SUCCESS;
00493   int             i;
00494 
00495   ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));
00496   ConReadBuf      = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));
00497   if((ConInstanceList == NULL) || (ConReadBuf == NULL))  {
00498     return RETURN_OUT_OF_RESOURCES;
00499   }
00500 
00501   for( i = 0; i < NUM_SPECIAL; ++i) {
00502     // Get pointer to instance.
00503     Stream = &ConInstanceList[i];
00504 
00505     Stream->Cookie      = CON_COOKIE;
00506     Stream->InstanceNum = i;
00507 
00508     switch(i) {
00509       case STDIN_FILENO:
00510         Stream->Dev = SystemTable->ConIn;
00511         break;
00512       case STDOUT_FILENO:
00513         Stream->Dev = SystemTable->ConOut;
00514         break;
00515       case STDERR_FILENO:
00516         if(SystemTable->StdErr == NULL) {
00517           Stream->Dev = SystemTable->ConOut;
00518         }
00519         else {
00520           Stream->Dev = SystemTable->StdErr;
00521         }
00522         break;
00523       default:
00524         return RETURN_VOLUME_CORRUPTED;     // This is a "should never happen" case.
00525     }
00526 
00527     Stream->Abstraction.fo_close    = &da_ConClose;
00528     Stream->Abstraction.fo_read     = &da_ConRead;
00529     Stream->Abstraction.fo_write    = &da_ConWrite;
00530     Stream->Abstraction.fo_stat     = &da_ConStat;
00531     Stream->Abstraction.fo_lseek    = &da_ConSeek;
00532     Stream->Abstraction.fo_fcntl    = &fnullop_fcntl;
00533     Stream->Abstraction.fo_ioctl    = &da_ConIoctl;
00534     Stream->Abstraction.fo_poll     = &da_ConPoll;
00535     Stream->Abstraction.fo_flush    = &fnullop_flush;
00536     Stream->Abstraction.fo_delete   = &fbadop_delete;
00537     Stream->Abstraction.fo_mkdir    = &fbadop_mkdir;
00538     Stream->Abstraction.fo_rmdir    = &fbadop_rmdir;
00539     Stream->Abstraction.fo_rename   = &fbadop_rename;
00540 
00541     Stream->NumRead     = 0;
00542     Stream->NumWritten  = 0;
00543     Stream->UnGetKey.ScanCode     = SCAN_NULL;
00544     Stream->UnGetKey.UnicodeChar  = CHAR_NULL;
00545 
00546     if(Stream->Dev == NULL) {
00547       continue;                 // No device for this stream.
00548     }
00549     ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]);
00550     if(ConNode[i] == NULL) {
00551       Status = EFIerrno;
00552       break;
00553     }
00554     Stream->Parent = ConNode[i];
00555   }
00556   /* Initialize Ioctl flags until Ioctl is really implemented. */
00557   TtyCooked = TRUE;
00558   TtyEcho   = TRUE;
00559 
00560   return  Status;
00561 }
00562 
00563 RETURN_STATUS
00564 EFIAPI
00565 __Cons_deconstruct(
00566   IN EFI_HANDLE        ImageHandle,
00567   IN EFI_SYSTEM_TABLE  *SystemTable
00568 )
00569 {
00570   int   i;
00571 
00572   for(i = 0; i < NUM_SPECIAL; ++i) {
00573     if(ConNode[i] != NULL) {
00574       FreePool(ConNode[i]);
00575     }
00576   }
00577   if(ConInstanceList != NULL) {
00578     FreePool(ConInstanceList);
00579   }
00580   if(ConReadBuf != NULL) {
00581     FreePool(ConReadBuf);
00582   }
00583 
00584   return RETURN_SUCCESS;
00585 }
00586 
00587 /* ######################################################################### */
00588 #if 0 /* Not implemented for Console */
00589 
00590 static
00591 int
00592 EFIAPI
00593 da_ConCntl(
00594   struct __filedes *filp,
00595   UINT32,
00596   void *,
00597   void *
00598   )
00599 {
00600 }
00601 
00602 static
00603 int
00604 EFIAPI
00605 da_ConFlush(
00606   struct __filedes *filp
00607   )
00608 {
00609   return 0;
00610 }
00611 #endif  /* Not implemented for Console */
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines