Path: blob/main/sys/contrib/dev/acpica/components/hardware/hwgpe.c
48521 views
/******************************************************************************1*2* Module Name: hwgpe - Low level GPE enable/disable/clear functions3*4*****************************************************************************/56/******************************************************************************7*8* 1. Copyright Notice9*10* Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp.11* All rights reserved.12*13* 2. License14*15* 2.1. This is your license from Intel Corp. under its intellectual property16* rights. You may have additional license terms from the party that provided17* you this software, covering your right to use that party's intellectual18* property rights.19*20* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a21* copy of the source code appearing in this file ("Covered Code") an22* irrevocable, perpetual, worldwide license under Intel's copyrights in the23* base code distributed originally by Intel ("Original Intel Code") to copy,24* make derivatives, distribute, use and display any portion of the Covered25* Code in any form, with the right to sublicense such rights; and26*27* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent28* license (with the right to sublicense), under only those claims of Intel29* patents that are infringed by the Original Intel Code, to make, use, sell,30* offer to sell, and import the Covered Code and derivative works thereof31* solely to the minimum extent necessary to exercise the above copyright32* license, and in no event shall the patent license extend to any additions33* to or modifications of the Original Intel Code. No other license or right34* is granted directly or by implication, estoppel or otherwise;35*36* The above copyright and patent license is granted only if the following37* conditions are met:38*39* 3. Conditions40*41* 3.1. Redistribution of Source with Rights to Further Distribute Source.42* Redistribution of source code of any substantial portion of the Covered43* Code or modification with rights to further distribute source must include44* the above Copyright Notice, the above License, this list of Conditions,45* and the following Disclaimer and Export Compliance provision. In addition,46* Licensee must cause all Covered Code to which Licensee contributes to47* contain a file documenting the changes Licensee made to create that Covered48* Code and the date of any change. Licensee must include in that file the49* documentation of any changes made by any predecessor Licensee. Licensee50* must include a prominent statement that the modification is derived,51* directly or indirectly, from Original Intel Code.52*53* 3.2. Redistribution of Source with no Rights to Further Distribute Source.54* Redistribution of source code of any substantial portion of the Covered55* Code or modification without rights to further distribute source must56* include the following Disclaimer and Export Compliance provision in the57* documentation and/or other materials provided with distribution. In58* addition, Licensee may not authorize further sublicense of source of any59* portion of the Covered Code, and must include terms to the effect that the60* license from Licensee to its licensee is limited to the intellectual61* property embodied in the software Licensee provides to its licensee, and62* not to intellectual property embodied in modifications its licensee may63* make.64*65* 3.3. Redistribution of Executable. Redistribution in executable form of any66* substantial portion of the Covered Code or modification must reproduce the67* above Copyright Notice, and the following Disclaimer and Export Compliance68* provision in the documentation and/or other materials provided with the69* distribution.70*71* 3.4. Intel retains all right, title, and interest in and to the Original72* Intel Code.73*74* 3.5. Neither the name Intel nor any other trademark owned or controlled by75* Intel shall be used in advertising or otherwise to promote the sale, use or76* other dealings in products derived from or relating to the Covered Code77* without prior written authorization from Intel.78*79* 4. Disclaimer and Export Compliance80*81* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED82* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE83* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,84* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY85* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY86* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A87* PARTICULAR PURPOSE.88*89* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES90* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR91* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,92* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY93* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL94* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS95* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY96* LIMITED REMEDY.97*98* 4.3. Licensee shall not export, either directly or indirectly, any of this99* software or system incorporating such software without first obtaining any100* required license or other approval from the U. S. Department of Commerce or101* any other agency or department of the United States Government. In the102* event Licensee exports any such software from the United States or103* re-exports any such software from a foreign destination, Licensee shall104* ensure that the distribution and export/re-export of the software is in105* compliance with all laws, regulations, orders, or other restrictions of the106* U.S. Export Administration Regulations. Licensee agrees that neither it nor107* any of its subsidiaries will export/re-export any technical data, process,108* software, or service, directly or indirectly, to any country for which the109* United States government or any agency thereof requires an export license,110* other governmental approval, or letter of assurance, without first obtaining111* such license, approval or letter.112*113*****************************************************************************114*115* Alternatively, you may choose to be licensed under the terms of the116* following license:117*118* Redistribution and use in source and binary forms, with or without119* modification, are permitted provided that the following conditions120* are met:121* 1. Redistributions of source code must retain the above copyright122* notice, this list of conditions, and the following disclaimer,123* without modification.124* 2. Redistributions in binary form must reproduce at minimum a disclaimer125* substantially similar to the "NO WARRANTY" disclaimer below126* ("Disclaimer") and any redistribution must be conditioned upon127* including a substantially similar Disclaimer requirement for further128* binary redistribution.129* 3. Neither the names of the above-listed copyright holders nor the names130* of any contributors may be used to endorse or promote products derived131* from this software without specific prior written permission.132*133* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS134* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT135* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR136* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT137* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,138* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT139* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,140* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY141* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT142* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE143* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.144*145* Alternatively, you may choose to be licensed under the terms of the146* GNU General Public License ("GPL") version 2 as published by the Free147* Software Foundation.148*149*****************************************************************************/150151#include <contrib/dev/acpica/include/acpi.h>152#include <contrib/dev/acpica/include/accommon.h>153#include <contrib/dev/acpica/include/acevents.h>154155#define _COMPONENT ACPI_HARDWARE156ACPI_MODULE_NAME ("hwgpe")157158#if (!ACPI_REDUCED_HARDWARE) /* Entire module */159160/* Local prototypes */161162static ACPI_STATUS163AcpiHwEnableWakeupGpeBlock (164ACPI_GPE_XRUPT_INFO *GpeXruptInfo,165ACPI_GPE_BLOCK_INFO *GpeBlock,166void *Context);167168static ACPI_STATUS169AcpiHwGpeEnableWrite (170UINT8 EnableMask,171ACPI_GPE_REGISTER_INFO *GpeRegisterInfo);172173174/******************************************************************************175*176* FUNCTION: AcpiHwGetGpeRegisterBit177*178* PARAMETERS: GpeEventInfo - Info block for the GPE179*180* RETURN: Register mask with a one in the GPE bit position181*182* DESCRIPTION: Compute the register mask for this GPE. One bit is set in the183* correct position for the input GPE.184*185******************************************************************************/186187UINT32188AcpiHwGetGpeRegisterBit (189ACPI_GPE_EVENT_INFO *GpeEventInfo)190{191192return ((UINT32) 1 <<193(GpeEventInfo->GpeNumber - GpeEventInfo->RegisterInfo->BaseGpeNumber));194}195196197/******************************************************************************198*199* FUNCTION: AcpiHwLowSetGpe200*201* PARAMETERS: GpeEventInfo - Info block for the GPE to be disabled202* Action - Enable or disable203*204* RETURN: Status205*206* DESCRIPTION: Enable or disable a single GPE in the parent enable register.207* The EnableMask field of the involved GPE register must be208* updated by the caller if necessary.209*210******************************************************************************/211212ACPI_STATUS213AcpiHwLowSetGpe (214ACPI_GPE_EVENT_INFO *GpeEventInfo,215UINT32 Action)216{217ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;218ACPI_STATUS Status = AE_OK;219UINT64 EnableMask;220UINT32 RegisterBit;221222223ACPI_FUNCTION_ENTRY ();224225226/* Get the info block for the entire GPE register */227228GpeRegisterInfo = GpeEventInfo->RegisterInfo;229if (!GpeRegisterInfo)230{231return (AE_NOT_EXIST);232}233234/* Get current value of the enable register that contains this GPE */235236Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress);237if (ACPI_FAILURE (Status))238{239return (Status);240}241242/* Set or clear just the bit that corresponds to this GPE */243244RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);245switch (Action)246{247case ACPI_GPE_CONDITIONAL_ENABLE:248249/* Only enable if the corresponding EnableMask bit is set */250251if (!(RegisterBit & GpeRegisterInfo->EnableMask))252{253return (AE_BAD_PARAMETER);254}255256ACPI_FALLTHROUGH;257258case ACPI_GPE_ENABLE:259260ACPI_SET_BIT (EnableMask, RegisterBit);261break;262263case ACPI_GPE_DISABLE:264265ACPI_CLEAR_BIT (EnableMask, RegisterBit);266break;267268default:269270ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u", Action));271return (AE_BAD_PARAMETER);272}273274if (!(RegisterBit & GpeRegisterInfo->MaskForRun))275{276/* Write the updated enable mask */277278Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);279}280return (Status);281}282283284/******************************************************************************285*286* FUNCTION: AcpiHwClearGpe287*288* PARAMETERS: GpeEventInfo - Info block for the GPE to be cleared289*290* RETURN: Status291*292* DESCRIPTION: Clear the status bit for a single GPE.293*294******************************************************************************/295296ACPI_STATUS297AcpiHwClearGpe (298ACPI_GPE_EVENT_INFO *GpeEventInfo)299{300ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;301ACPI_STATUS Status;302UINT32 RegisterBit;303304305ACPI_FUNCTION_ENTRY ();306307/* Get the info block for the entire GPE register */308309GpeRegisterInfo = GpeEventInfo->RegisterInfo;310if (!GpeRegisterInfo)311{312return (AE_NOT_EXIST);313}314315/*316* Write a one to the appropriate bit in the status register to317* clear this GPE.318*/319RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);320321Status = AcpiHwWrite (RegisterBit, &GpeRegisterInfo->StatusAddress);322return (Status);323}324325326/******************************************************************************327*328* FUNCTION: AcpiHwGetGpeStatus329*330* PARAMETERS: GpeEventInfo - Info block for the GPE to queried331* EventStatus - Where the GPE status is returned332*333* RETURN: Status334*335* DESCRIPTION: Return the status of a single GPE.336*337******************************************************************************/338339ACPI_STATUS340AcpiHwGetGpeStatus (341ACPI_GPE_EVENT_INFO *GpeEventInfo,342ACPI_EVENT_STATUS *EventStatus)343{344UINT64 InByte;345UINT32 RegisterBit;346ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;347ACPI_EVENT_STATUS LocalEventStatus = 0;348ACPI_STATUS Status;349350351ACPI_FUNCTION_ENTRY ();352353354if (!EventStatus)355{356return (AE_BAD_PARAMETER);357}358359/* GPE currently handled? */360361if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) !=362ACPI_GPE_DISPATCH_NONE)363{364LocalEventStatus |= ACPI_EVENT_FLAG_HAS_HANDLER;365}366367/* Get the info block for the entire GPE register */368369GpeRegisterInfo = GpeEventInfo->RegisterInfo;370371/* Get the register bitmask for this GPE */372373RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);374375/* GPE currently enabled? (enabled for runtime?) */376377if (RegisterBit & GpeRegisterInfo->EnableForRun)378{379LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;380}381382/* GPE currently masked? (masked for runtime?) */383384if (RegisterBit & GpeRegisterInfo->MaskForRun)385{386LocalEventStatus |= ACPI_EVENT_FLAG_MASKED;387}388389/* GPE enabled for wake? */390391if (RegisterBit & GpeRegisterInfo->EnableForWake)392{393LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED;394}395396/* GPE currently enabled (enable bit == 1)? */397398Status = AcpiHwRead (&InByte, &GpeRegisterInfo->EnableAddress);399if (ACPI_FAILURE (Status))400{401return (Status);402}403404if (RegisterBit & InByte)405{406LocalEventStatus |= ACPI_EVENT_FLAG_ENABLE_SET;407}408409/* GPE currently active (status bit == 1)? */410411Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress);412if (ACPI_FAILURE (Status))413{414return (Status);415}416417if (RegisterBit & InByte)418{419LocalEventStatus |= ACPI_EVENT_FLAG_STATUS_SET;420}421422/* Set return value */423424(*EventStatus) = LocalEventStatus;425return (AE_OK);426}427428429/******************************************************************************430*431* FUNCTION: AcpiHwGpeEnableWrite432*433* PARAMETERS: EnableMask - Bit mask to write to the GPE register434* GpeRegisterInfo - Gpe Register info435*436* RETURN: Status437*438* DESCRIPTION: Write the enable mask byte to the given GPE register.439*440******************************************************************************/441442static ACPI_STATUS443AcpiHwGpeEnableWrite (444UINT8 EnableMask,445ACPI_GPE_REGISTER_INFO *GpeRegisterInfo)446{447ACPI_STATUS Status;448449450GpeRegisterInfo->EnableMask = EnableMask;451452Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);453return (Status);454}455456457/******************************************************************************458*459* FUNCTION: AcpiHwDisableGpeBlock460*461* PARAMETERS: GpeXruptInfo - GPE Interrupt info462* GpeBlock - Gpe Block info463*464* RETURN: Status465*466* DESCRIPTION: Disable all GPEs within a single GPE block467*468******************************************************************************/469470ACPI_STATUS471AcpiHwDisableGpeBlock (472ACPI_GPE_XRUPT_INFO *GpeXruptInfo,473ACPI_GPE_BLOCK_INFO *GpeBlock,474void *Context)475{476UINT32 i;477ACPI_STATUS Status;478479480/* Examine each GPE Register within the block */481482for (i = 0; i < GpeBlock->RegisterCount; i++)483{484/* Disable all GPEs in this register */485486Status = AcpiHwGpeEnableWrite (0x00, &GpeBlock->RegisterInfo[i]);487if (ACPI_FAILURE (Status))488{489return (Status);490}491}492493return (AE_OK);494}495496497/******************************************************************************498*499* FUNCTION: AcpiHwClearGpeBlock500*501* PARAMETERS: GpeXruptInfo - GPE Interrupt info502* GpeBlock - Gpe Block info503*504* RETURN: Status505*506* DESCRIPTION: Clear status bits for all GPEs within a single GPE block507*508******************************************************************************/509510ACPI_STATUS511AcpiHwClearGpeBlock (512ACPI_GPE_XRUPT_INFO *GpeXruptInfo,513ACPI_GPE_BLOCK_INFO *GpeBlock,514void *Context)515{516UINT32 i;517ACPI_STATUS Status;518519520/* Examine each GPE Register within the block */521522for (i = 0; i < GpeBlock->RegisterCount; i++)523{524/* Clear status on all GPEs in this register */525526Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress);527if (ACPI_FAILURE (Status))528{529return (Status);530}531}532533return (AE_OK);534}535536537/******************************************************************************538*539* FUNCTION: AcpiHwEnableRuntimeGpeBlock540*541* PARAMETERS: GpeXruptInfo - GPE Interrupt info542* GpeBlock - Gpe Block info543*544* RETURN: Status545*546* DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes547* combination wake/run GPEs.548*549******************************************************************************/550551ACPI_STATUS552AcpiHwEnableRuntimeGpeBlock (553ACPI_GPE_XRUPT_INFO *GpeXruptInfo,554ACPI_GPE_BLOCK_INFO *GpeBlock,555void *Context)556{557UINT32 i;558ACPI_STATUS Status;559ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;560UINT8 EnableMask;561562563/* NOTE: assumes that all GPEs are currently disabled */564565/* Examine each GPE Register within the block */566567for (i = 0; i < GpeBlock->RegisterCount; i++)568{569GpeRegisterInfo = &GpeBlock->RegisterInfo[i];570if (!GpeRegisterInfo->EnableForRun)571{572continue;573}574575/* Enable all "runtime" GPEs in this register */576577EnableMask = GpeRegisterInfo->EnableForRun &578~GpeRegisterInfo->MaskForRun;579Status = AcpiHwGpeEnableWrite (EnableMask, GpeRegisterInfo);580if (ACPI_FAILURE (Status))581{582return (Status);583}584}585586return (AE_OK);587}588589590/******************************************************************************591*592* FUNCTION: AcpiHwEnableWakeupGpeBlock593*594* PARAMETERS: GpeXruptInfo - GPE Interrupt info595* GpeBlock - Gpe Block info596*597* RETURN: Status598*599* DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes600* combination wake/run GPEs.601*602******************************************************************************/603604static ACPI_STATUS605AcpiHwEnableWakeupGpeBlock (606ACPI_GPE_XRUPT_INFO *GpeXruptInfo,607ACPI_GPE_BLOCK_INFO *GpeBlock,608void *Context)609{610UINT32 i;611ACPI_STATUS Status;612ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;613614615/* Examine each GPE Register within the block */616617for (i = 0; i < GpeBlock->RegisterCount; i++)618{619GpeRegisterInfo = &GpeBlock->RegisterInfo[i];620621/*622* Enable all "wake" GPEs in this register and disable the623* remaining ones.624*/625Status = AcpiHwGpeEnableWrite (GpeRegisterInfo->EnableForWake,626GpeRegisterInfo);627if (ACPI_FAILURE (Status))628{629return (Status);630}631}632633return (AE_OK);634}635636637/******************************************************************************638*639* FUNCTION: AcpiHwGetGpeBlockStatus640*641* PARAMETERS: GpeXruptInfo - GPE Interrupt info642* GpeBlock - Gpe Block info643*644* RETURN: Success645*646* DESCRIPTION: Produce a combined GPE status bits mask for the given block.647*648******************************************************************************/649650static ACPI_STATUS651AcpiHwGetGpeBlockStatus(652ACPI_GPE_XRUPT_INFO *GpeXruptInfo,653ACPI_GPE_BLOCK_INFO *GpeBlock,654void *RetPtr)655{656ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;657UINT64 InEnable;658UINT64 InStatus;659ACPI_STATUS Status;660UINT8 *Ret = RetPtr;661UINT32 i;662663664/* Examine each GPE Register within the block */665666for (i = 0; i < GpeBlock->RegisterCount; i++)667{668GpeRegisterInfo = &GpeBlock->RegisterInfo[i];669670Status = AcpiHwRead (&InEnable, &GpeRegisterInfo->EnableAddress);671if (ACPI_FAILURE (Status))672{673continue;674}675676Status = AcpiHwRead (&InStatus, &GpeRegisterInfo->StatusAddress);677if (ACPI_FAILURE (Status))678{679continue;680}681682*Ret |= InEnable & InStatus;683}684685return (AE_OK);686}687688689/******************************************************************************690*691* FUNCTION: AcpiHwDisableAllGpes692*693* PARAMETERS: None694*695* RETURN: Status696*697* DESCRIPTION: Disable and clear all GPEs in all GPE blocks698*699******************************************************************************/700701ACPI_STATUS702AcpiHwDisableAllGpes (703void)704{705ACPI_STATUS Status;706707708ACPI_FUNCTION_TRACE (HwDisableAllGpes);709710711Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL);712return_ACPI_STATUS (Status);713}714715716/******************************************************************************717*718* FUNCTION: AcpiHwEnableAllRuntimeGpes719*720* PARAMETERS: None721*722* RETURN: Status723*724* DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks725*726******************************************************************************/727728ACPI_STATUS729AcpiHwEnableAllRuntimeGpes (730void)731{732ACPI_STATUS Status;733734735ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes);736737738Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL);739return_ACPI_STATUS (Status);740}741742743/******************************************************************************744*745* FUNCTION: AcpiHwEnableAllWakeupGpes746*747* PARAMETERS: None748*749* RETURN: Status750*751* DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks752*753******************************************************************************/754755ACPI_STATUS756AcpiHwEnableAllWakeupGpes (757void)758{759ACPI_STATUS Status;760761762ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes);763764765Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL);766return_ACPI_STATUS (Status);767}768769770/******************************************************************************771*772* FUNCTION: AcpiHwCheckAllGpes773*774* PARAMETERS: None775*776* RETURN: Combined status of all GPEs777*778* DESCRIPTION: Check all enabled GPEs in all GPE blocks and return TRUE if the779* status bit is set for at least one of them of FALSE otherwise.780*781******************************************************************************/782783UINT8784AcpiHwCheckAllGpes (785void)786{787UINT8 Ret = 0;788789790ACPI_FUNCTION_TRACE (AcpiHwCheckAllGpes);791792(void) AcpiEvWalkGpeList (AcpiHwGetGpeBlockStatus, &Ret);793return (Ret != 0);794}795796#endif /* !ACPI_REDUCED_HARDWARE */797798799