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

IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.c

Go to the documentation of this file.
00001 
00016 #include "Hotkey.h"
00017 
00018 
00019 LIST_ENTRY        mHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList);
00020 BDS_COMMON_OPTION *mHotkeyBootOption = NULL;
00021 EFI_EVENT         mHotkeyEvent;
00022 VOID              *mHotkeyRegistration;
00023 
00024 
00034 BOOLEAN
00035 IsKeyOptionValid (
00036   IN EFI_KEY_OPTION     *KeyOption
00037 )
00038 {
00039   UINT16   BootOptionName[10];
00040   UINT8    *BootOptionVar;
00041   UINTN    BootOptionSize;
00042   UINT32   Crc;
00043 
00044   //
00045   // Check whether corresponding Boot Option exist
00046   //
00047   UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", KeyOption->BootOption);
00048   BootOptionVar = BdsLibGetVariableAndSize (
00049                     BootOptionName,
00050                     &gEfiGlobalVariableGuid,
00051                     &BootOptionSize
00052                     );
00053 
00054   if (BootOptionVar == NULL || BootOptionSize == 0) {
00055     return FALSE;
00056   }
00057 
00058   //
00059   // Check CRC for Boot Option
00060   //
00061   gBS->CalculateCrc32 (BootOptionVar, BootOptionSize, &Crc);
00062   FreePool (BootOptionVar);
00063 
00064   return (BOOLEAN) ((KeyOption->BootOptionCrc == Crc) ? TRUE : FALSE);
00065 }
00066 
00078 EFI_STATUS
00079 RegisterHotkey (
00080   IN EFI_KEY_OPTION     *KeyOption,
00081   OUT UINT16            *KeyOptionNumber
00082 )
00083 {
00084   UINT16          KeyOptionName[10];
00085   UINT16          *KeyOrder;
00086   UINTN           KeyOrderSize;
00087   UINT16          *NewKeyOrder;
00088   UINTN           Index;
00089   UINT16          MaxOptionNumber;
00090   UINT16          RegisterOptionNumber;
00091   EFI_KEY_OPTION  *TempOption;
00092   UINTN           TempOptionSize;
00093   EFI_STATUS      Status;
00094   UINTN           KeyOptionSize;
00095   BOOLEAN         UpdateBootOption;
00096 
00097   //
00098   // Validate the given key option
00099   //
00100   if (!IsKeyOptionValid (KeyOption)) {
00101     return EFI_INVALID_PARAMETER;
00102   }
00103 
00104   KeyOptionSize = sizeof (EFI_KEY_OPTION) + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);
00105   UpdateBootOption = FALSE;
00106 
00107   //
00108   // Check whether HotKey conflict with keys used by Setup Browser
00109   //
00110   KeyOrder = BdsLibGetVariableAndSize (
00111                VAR_KEY_ORDER,
00112                &gEfiGlobalVariableGuid,
00113                &KeyOrderSize
00114                );
00115   if (KeyOrder == NULL) {
00116     KeyOrderSize = 0;
00117   }
00118 
00119   //
00120   // Find free key option number
00121   //
00122   MaxOptionNumber = 0;
00123   TempOption = NULL;
00124   for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) {
00125     if (MaxOptionNumber < KeyOrder[Index]) {
00126       MaxOptionNumber = KeyOrder[Index];
00127     }
00128 
00129     UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]);
00130     TempOption = BdsLibGetVariableAndSize (
00131                    KeyOptionName,
00132                    &gEfiGlobalVariableGuid,
00133                    &TempOptionSize
00134                    );
00135     ASSERT (TempOption != NULL);
00136 
00137     if (CompareMem (TempOption, KeyOption, TempOptionSize) == 0) {
00138       //
00139       // Got the option, so just return
00140       //
00141       FreePool (TempOption);
00142       FreePool (KeyOrder);
00143       return EFI_SUCCESS;
00144     }
00145 
00146     if (KeyOption->KeyData.PackedValue == TempOption->KeyData.PackedValue) {
00147       if (KeyOption->KeyData.Options.InputKeyCount == 0 ||
00148           CompareMem (
00149             ((UINT8 *) TempOption) + sizeof (EFI_KEY_OPTION),
00150             ((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION),
00151             KeyOptionSize - sizeof (EFI_KEY_OPTION)
00152             ) == 0) {
00153           //
00154           // Hotkey is the same but BootOption changed, need update
00155           //
00156           UpdateBootOption = TRUE;
00157           break;
00158       }
00159     }
00160 
00161     FreePool (TempOption);
00162   }
00163 
00164   if (UpdateBootOption) {
00165     RegisterOptionNumber = KeyOrder[Index];
00166     FreePool (TempOption);
00167   } else {
00168     RegisterOptionNumber = (UINT16) (MaxOptionNumber + 1);
00169   }
00170 
00171   if (KeyOptionNumber != NULL) {
00172     *KeyOptionNumber = RegisterOptionNumber;
00173   }
00174 
00175   //
00176   // Create variable Key####
00177   //
00178   UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", RegisterOptionNumber);
00179   Status = gRT->SetVariable (
00180                   KeyOptionName,
00181                   &gEfiGlobalVariableGuid,
00182                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
00183                   KeyOptionSize,
00184                   KeyOption
00185                   );
00186   if (EFI_ERROR (Status)) {
00187     FreePool (KeyOrder);
00188     return Status;
00189   }
00190 
00191   //
00192   // Update the key order variable - "KeyOrder"
00193   //
00194   if (!UpdateBootOption) {
00195     Index = KeyOrderSize / sizeof (UINT16);
00196     KeyOrderSize += sizeof (UINT16);
00197   }
00198 
00199   NewKeyOrder = AllocatePool (KeyOrderSize);
00200   if (NewKeyOrder == NULL) {
00201     FreePool (KeyOrder);
00202     return EFI_OUT_OF_RESOURCES;
00203   }
00204 
00205   if (KeyOrder != NULL) {
00206     CopyMem (NewKeyOrder, KeyOrder, KeyOrderSize);
00207   }
00208 
00209   NewKeyOrder[Index] = RegisterOptionNumber;
00210 
00211   Status = gRT->SetVariable (
00212                   VAR_KEY_ORDER,
00213                   &gEfiGlobalVariableGuid,
00214                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
00215                   KeyOrderSize,
00216                   NewKeyOrder
00217                   );
00218 
00219   FreePool (KeyOrder);
00220   FreePool (NewKeyOrder);
00221 
00222   return Status;
00223 }
00224 
00235 EFI_STATUS
00236 UnregisterHotkey (
00237   IN UINT16     KeyOptionNumber
00238 )
00239 {
00240   UINT16      KeyOption[10];
00241   UINTN       Index;
00242   EFI_STATUS  Status;
00243   UINTN       Index2Del;
00244   UINT16      *KeyOrder;
00245   UINTN       KeyOrderSize;
00246 
00247   //
00248   // Delete variable Key####
00249   //
00250   UnicodeSPrint (KeyOption, sizeof (KeyOption), L"Key%04x", KeyOptionNumber);
00251   gRT->SetVariable (
00252          KeyOption,
00253          &gEfiGlobalVariableGuid,
00254          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
00255          0,
00256          NULL
00257          );
00258 
00259   //
00260   // Adjust key order array
00261   //
00262   KeyOrder = BdsLibGetVariableAndSize (
00263                VAR_KEY_ORDER,
00264                &gEfiGlobalVariableGuid,
00265                &KeyOrderSize
00266                );
00267   if (KeyOrder == NULL) {
00268     return EFI_SUCCESS;
00269   }
00270 
00271   Index2Del = 0;
00272   for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) {
00273     if (KeyOrder[Index] == KeyOptionNumber) {
00274       Index2Del = Index;
00275       break;
00276     }
00277   }
00278 
00279   if (Index != KeyOrderSize / sizeof (UINT16)) {
00280     //
00281     // KeyOptionNumber found in "KeyOrder", delete it
00282     //
00283     for (Index = Index2Del; Index < KeyOrderSize / sizeof (UINT16) - 1; Index++) {
00284       KeyOrder[Index] = KeyOrder[Index + 1];
00285     }
00286 
00287     KeyOrderSize -= sizeof (UINT16);
00288   }
00289 
00290   Status = gRT->SetVariable (
00291                   VAR_KEY_ORDER,
00292                   &gEfiGlobalVariableGuid,
00293                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
00294                   KeyOrderSize,
00295                   KeyOrder
00296                   );
00297 
00298   FreePool (KeyOrder);
00299 
00300   return Status;
00301 }
00302 
00306 VOID
00307 HotkeyBoot (
00308   VOID
00309   )
00310 {
00311   EFI_STATUS           Status;
00312   UINTN                ExitDataSize;
00313   CHAR16               *ExitData;
00314   
00315   if (mHotkeyBootOption != NULL) {
00316     BdsLibConnectDevicePath (mHotkeyBootOption->DevicePath);
00317 
00318     //
00319     // Clear the screen before launch this BootOption
00320     //
00321     gST->ConOut->Reset (gST->ConOut, FALSE);
00322 
00323     Status = BdsLibBootViaBootOption (mHotkeyBootOption, mHotkeyBootOption->DevicePath, &ExitDataSize, &ExitData);
00324 
00325     if (EFI_ERROR (Status)) {
00326       //
00327       // Call platform action to indicate the boot fail
00328       //
00329       mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
00330       PlatformBdsBootFail (mHotkeyBootOption, Status, ExitData, ExitDataSize);
00331     } else {
00332       //
00333       // Call platform action to indicate the boot success
00334       //
00335       mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
00336       PlatformBdsBootSuccess (mHotkeyBootOption);
00337     }
00338     FreePool (mHotkeyBootOption->Description);
00339     FreePool (mHotkeyBootOption->DevicePath);
00340     FreePool (mHotkeyBootOption->LoadOptions);
00341     FreePool (mHotkeyBootOption);
00342 
00343     mHotkeyBootOption = NULL;
00344   }
00345 }
00346 
00358 EFI_STATUS
00359 EFIAPI
00360 HotkeyCallback (
00361   IN EFI_KEY_DATA     *KeyData
00362 )
00363 {
00364   BOOLEAN            HotkeyCatched;
00365   LIST_ENTRY         BootLists;
00366   LIST_ENTRY         *Link;
00367   BDS_HOTKEY_OPTION  *Hotkey;
00368   UINT16             Buffer[10];
00369   EFI_STATUS         Status;
00370   EFI_KEY_DATA       *HotkeyData;
00371 
00372   if (mHotkeyBootOption != NULL) {
00373     //
00374     // Do not process sequential hotkey stroke until the current boot option returns
00375     //
00376     return EFI_SUCCESS;
00377   }
00378 
00379   Status                 = EFI_SUCCESS;
00380 
00381   for ( Link = GetFirstNode (&mHotkeyList)
00382       ; !IsNull (&mHotkeyList, Link)
00383       ; Link = GetNextNode (&mHotkeyList, Link)
00384       ) {
00385     HotkeyCatched = FALSE;
00386     Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
00387 
00388     //
00389     // Is this Key Stroke we are waiting for?
00390     //
00391     ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
00392     HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
00393     if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
00394         (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
00395         (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? 
00396           (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
00397         )
00398        ) {
00399       //
00400       // For hotkey of key combination, transit to next waiting state
00401       //
00402       Hotkey->WaitingKey++;
00403 
00404       if (Hotkey->WaitingKey == Hotkey->CodeCount) {
00405         //
00406         // Received the whole key stroke sequence
00407         //
00408         HotkeyCatched = TRUE;
00409       }
00410     } else {
00411       //
00412       // Receive an unexpected key stroke, reset to initial waiting state
00413       //
00414       Hotkey->WaitingKey = 0;
00415     }
00416 
00417     if (HotkeyCatched) {
00418       //
00419       // Reset to initial waiting state
00420       //
00421       Hotkey->WaitingKey = 0;
00422 
00423       //
00424       // Launch its BootOption
00425       //
00426       InitializeListHead (&BootLists);
00427 
00428       UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
00429       mHotkeyBootOption = BdsLibVariableToOption (&BootLists, Buffer);
00430     }
00431   }
00432 
00433   return Status;
00434 }
00435 
00445 EFI_STATUS
00446 HotkeyRegisterNotify (
00447   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *SimpleTextInEx
00448 )
00449 {
00450   UINTN              Index;
00451   EFI_STATUS         Status;
00452   LIST_ENTRY         *Link;
00453   BDS_HOTKEY_OPTION  *Hotkey;
00454 
00455   //
00456   // Register notification function for each hotkey
00457   //
00458   Link = GetFirstNode (&mHotkeyList);
00459 
00460   while (!IsNull (&mHotkeyList, Link)) {
00461     Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
00462 
00463     Index = 0;
00464     do {
00465       Status = SimpleTextInEx->RegisterKeyNotify (
00466                                  SimpleTextInEx,
00467                                  &Hotkey->KeyData[Index],
00468                                  HotkeyCallback,
00469                                  &Hotkey->NotifyHandle
00470                                  );
00471       if (EFI_ERROR (Status)) {
00472         //
00473         // some of the hotkey registry failed
00474         //
00475         return Status;
00476       }
00477       Index ++;
00478     } while ((Index < Hotkey->CodeCount) && (Index < (sizeof (Hotkey->KeyData) / sizeof (EFI_KEY_DATA))));
00479 
00480     Link = GetNextNode (&mHotkeyList, Link);
00481   }
00482 
00483   return EFI_SUCCESS;
00484 }
00485 
00493 VOID
00494 EFIAPI
00495 HotkeyEvent (
00496   IN EFI_EVENT    Event,
00497   IN VOID         *Context
00498   )
00499 {
00500   EFI_STATUS                         Status;
00501   UINTN                              BufferSize;
00502   EFI_HANDLE                         Handle;
00503   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *SimpleTextInEx;
00504 
00505   while (TRUE) {
00506     BufferSize = sizeof (EFI_HANDLE);
00507     Status = gBS->LocateHandle (
00508                     ByRegisterNotify,
00509                     NULL,
00510                     mHotkeyRegistration,
00511                     &BufferSize,
00512                     &Handle
00513                     );
00514     if (EFI_ERROR (Status)) {
00515       //
00516       // If no more notification events exist
00517       //
00518       return ;
00519     }
00520 
00521     Status = gBS->HandleProtocol (
00522                     Handle,
00523                     &gEfiSimpleTextInputExProtocolGuid,
00524                     (VOID **) &SimpleTextInEx
00525                     );
00526     ASSERT_EFI_ERROR (Status);
00527 
00528     HotkeyRegisterNotify (SimpleTextInEx);
00529   }
00530 }
00531 
00540 EFI_STATUS
00541 HotkeyInsertList (
00542   IN EFI_KEY_OPTION     *KeyOption
00543 )
00544 {
00545   BDS_HOTKEY_OPTION  *HotkeyLeft;
00546   BDS_HOTKEY_OPTION  *HotkeyRight;
00547   UINTN              Index;
00548   EFI_BOOT_KEY_DATA  KeyOptions;
00549   UINT32             KeyShiftStateLeft;
00550   UINT32             KeyShiftStateRight;
00551   EFI_INPUT_KEY      *InputKey;
00552   EFI_KEY_DATA       *KeyData;
00553 
00554   HotkeyLeft = AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION));
00555   if (HotkeyLeft == NULL) {
00556     return EFI_OUT_OF_RESOURCES;
00557   }
00558 
00559   HotkeyLeft->Signature = BDS_HOTKEY_OPTION_SIGNATURE;
00560   HotkeyLeft->BootOptionNumber = KeyOption->BootOption;
00561 
00562   KeyOptions = KeyOption->KeyData;
00563 
00564   HotkeyLeft->CodeCount = (UINT8) KeyOptions.Options.InputKeyCount;
00565 
00566   //
00567   // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
00568   //
00569   KeyShiftStateRight = EFI_SHIFT_STATE_VALID;
00570   if (KeyOptions.Options.ShiftPressed) {
00571     KeyShiftStateRight |= EFI_RIGHT_SHIFT_PRESSED;
00572   }
00573   if (KeyOptions.Options.ControlPressed) {
00574     KeyShiftStateRight |= EFI_RIGHT_CONTROL_PRESSED;
00575   }
00576   if (KeyOptions.Options.AltPressed) {
00577     KeyShiftStateRight |= EFI_RIGHT_ALT_PRESSED;
00578   }
00579   if (KeyOptions.Options.LogoPressed) {
00580     KeyShiftStateRight |= EFI_RIGHT_LOGO_PRESSED;
00581   }
00582   if (KeyOptions.Options.MenuPressed) {
00583     KeyShiftStateRight |= EFI_MENU_KEY_PRESSED;
00584   }
00585   if (KeyOptions.Options.SysReqPressed) {
00586     KeyShiftStateRight |= EFI_SYS_REQ_PRESSED;
00587   }
00588 
00589 
00590   KeyShiftStateLeft = (KeyShiftStateRight & 0xffffff00) | ((KeyShiftStateRight & 0xff) << 1);
00591 
00592   InputKey = (EFI_INPUT_KEY *) (((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION));
00593 
00594   Index = 0;
00595   KeyData = &HotkeyLeft->KeyData[0];
00596   do {
00597     //
00598     // If Key CodeCount is 0, then only KeyData[0] is used;
00599     // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
00600     //
00601     KeyData->Key.ScanCode = InputKey[Index].ScanCode;
00602     KeyData->Key.UnicodeChar = InputKey[Index].UnicodeChar;
00603     KeyData->KeyState.KeyShiftState = KeyShiftStateLeft;
00604 
00605     Index++;
00606     KeyData++;
00607   } while (Index < HotkeyLeft->CodeCount);
00608   InsertTailList (&mHotkeyList, &HotkeyLeft->Link);
00609 
00610   if (KeyShiftStateLeft != KeyShiftStateRight) {
00611     //
00612     // Need an extra hotkey for shift key on right
00613     //
00614     HotkeyRight = AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION), HotkeyLeft);
00615     if (HotkeyRight == NULL) {
00616       return EFI_OUT_OF_RESOURCES;
00617     }
00618 
00619     Index = 0;
00620     KeyData = &HotkeyRight->KeyData[0];
00621     do {
00622       //
00623       // Key.ScanCode and Key.UnicodeChar have already been initialized,
00624       // only need to update KeyState.KeyShiftState
00625       //
00626       KeyData->KeyState.KeyShiftState = KeyShiftStateRight;
00627 
00628       Index++;
00629       KeyData++;
00630     } while (Index < HotkeyRight->CodeCount);
00631     InsertTailList (&mHotkeyList, &HotkeyRight->Link);
00632   }
00633 
00634   return EFI_SUCCESS;
00635 }
00636 
00644 EFI_STATUS
00645 InitializeHotkeyService (
00646   VOID
00647   )
00648 {
00649   EFI_STATUS      Status;
00650   UINT32          BootOptionSupport;
00651   UINT16          *KeyOrder;
00652   UINTN           KeyOrderSize;
00653   UINTN           Index;
00654   UINT16          KeyOptionName[8];
00655   UINTN           KeyOptionSize;
00656   EFI_KEY_OPTION  *KeyOption;
00657 
00658   //
00659   // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
00660   // with maximum number of key presses of 3
00661   //
00662   BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_KEY | EFI_BOOT_OPTION_SUPPORT_APP;
00663   SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
00664   Status = gRT->SetVariable (
00665                   L"BootOptionSupport",
00666                   &gEfiGlobalVariableGuid,
00667                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
00668                   sizeof (UINT32),
00669                   &BootOptionSupport
00670                   );
00671 
00672   //
00673   // Get valid Key Option List from private EFI variable "KeyOrder"
00674   //
00675   KeyOrder = BdsLibGetVariableAndSize (
00676                VAR_KEY_ORDER,
00677                &gEfiGlobalVariableGuid,
00678                &KeyOrderSize
00679                );
00680 
00681   if (KeyOrder == NULL) {
00682     return EFI_NOT_FOUND;
00683   }
00684 
00685   for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index ++) {
00686     UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]);
00687     KeyOption = BdsLibGetVariableAndSize (
00688                   KeyOptionName,
00689                   &gEfiGlobalVariableGuid,
00690                   &KeyOptionSize
00691                   );
00692 
00693     if (KeyOption == NULL || !IsKeyOptionValid (KeyOption)) {
00694       UnregisterHotkey (KeyOrder[Index]);
00695     } else {
00696       HotkeyInsertList (KeyOption);
00697     }
00698   }
00699 
00700   //
00701   // Register Protocol notify for Hotkey service
00702   //
00703   Status = gBS->CreateEvent (
00704                   EVT_NOTIFY_SIGNAL,
00705                   TPL_CALLBACK,
00706                   HotkeyEvent,
00707                   NULL,
00708                   &mHotkeyEvent
00709                   );
00710   ASSERT_EFI_ERROR (Status);
00711 
00712   //
00713   // Register for protocol notifications on this event
00714   //
00715   Status = gBS->RegisterProtocolNotify (
00716                   &gEfiSimpleTextInputExProtocolGuid,
00717                   mHotkeyEvent,
00718                   &mHotkeyRegistration
00719                   );
00720   ASSERT_EFI_ERROR (Status);
00721 
00722   return Status;
00723 }
00724 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines