⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hwregs.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************* * * Module Name: hwregs - Read/write access functions for the various ACPI *                       control and status registers. *              $Revision: 86 $ * ******************************************************************************//* *  Copyright (C) 2000 R. Byron Moore * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "acpi.h"#include "achware.h"#include "acnamesp.h"#define _COMPONENT          HARDWARE	 MODULE_NAME         ("hwregs")/* This matches the #defines in actypes.h. */NATIVE_CHAR                 *sleep_state_table[] = {"\\_S0_","\\_S1_","\\_S2_","\\_S3_",			  "\\_S4_","\\_S4_b","\\_S5_"};/******************************************************************************* * * FUNCTION:    Acpi_hw_get_bit_shift * * PARAMETERS:  Mask            - Input mask to determine bit shift from. *                                Must have at least 1 bit set. * * RETURN:      Bit location of the lsb of the mask * * DESCRIPTION: Returns the bit number for the low order bit that's set. * ******************************************************************************/static u32acpi_hw_get_bit_shift (	u32                     mask){	u32                     shift;	for (shift = 0; ((mask >> shift) & 1) == 0; shift++) { ; }	return (shift);}/******************************************************************************* * * FUNCTION:    Acpi_hw_clear_acpi_status * * PARAMETERS:  none * * RETURN:      none * * DESCRIPTION: Clears all fixed and general purpose status bits * ******************************************************************************/voidacpi_hw_clear_acpi_status (void){	u16                     gpe_length;	u16                     index;	acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);	acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_STS, ALL_FIXED_STS_BITS);	if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address)) {		acpi_os_out16 ((ACPI_IO_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address),				  (u16) ALL_FIXED_STS_BITS);	}	/* now clear the GPE Bits */	if (acpi_gbl_FADT->gpe0blk_len) {		gpe_length = (u16) DIV_2 (acpi_gbl_FADT->gpe0blk_len);		for (index = 0; index < gpe_length; index++) {			acpi_os_out8 ((ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + index),					  (u8) 0xff);		}	}	if (acpi_gbl_FADT->gpe1_blk_len) {		gpe_length = (u16) DIV_2 (acpi_gbl_FADT->gpe1_blk_len);		for (index = 0; index < gpe_length; index++) {			acpi_os_out8 ((ACPI_IO_ADDRESS) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + index),					  (u8) 0xff);		}	}	acpi_cm_release_mutex (ACPI_MTX_HARDWARE);	return;}/******************************************************************************* * * FUNCTION:    Acpi_hw_obtain_sleep_type_register_data * * PARAMETERS:  Sleep_state       - Numeric state requested *              *Slp_Typ_a         - Pointer to byte to receive SLP_TYPa value *              *Slp_Typ_b         - Pointer to byte to receive SLP_TYPb value * * RETURN:      Status - ACPI status * * DESCRIPTION: Acpi_hw_obtain_sleep_type_register_data() obtains the SLP_TYP and *              SLP_TYPb values for the sleep state requested. * ******************************************************************************/ACPI_STATUSacpi_hw_obtain_sleep_type_register_data (	u8                      sleep_state,	u8                      *slp_typ_a,	u8                      *slp_typ_b){	ACPI_STATUS             status = AE_OK;	ACPI_OPERAND_OBJECT     *obj_desc;	/*	 *  Validate parameters	 */	if ((sleep_state > ACPI_S_STATES_MAX) ||		!slp_typ_a || !slp_typ_b)	{		return (AE_BAD_PARAMETER);	}	/*	 *  Acpi_evaluate the namespace object containing the values for this state	 */	status = acpi_ns_evaluate_by_name (sleep_state_table[sleep_state], NULL, &obj_desc);	if (ACPI_FAILURE (status)) {		return (status);	}	if (!obj_desc) {		REPORT_ERROR (("Missing Sleep State object\n"));		return (AE_NOT_EXIST);	}	/*	 *  We got something, now ensure it is correct.  The object must	 *  be a package and must have at least 2 numeric values as the	 *  two elements	 */	status = acpi_cm_resolve_package_references(obj_desc);	if (obj_desc->package.count < 2) {		/* Must have at least two elements */		REPORT_ERROR (("Sleep State package does not have at least two elements\n"));		status = AE_ERROR;	}	else if (((obj_desc->package.elements[0])->common.type !=			 ACPI_TYPE_NUMBER) ||			 ((obj_desc->package.elements[1])->common.type !=				ACPI_TYPE_NUMBER))	{		/* Must have two  */		REPORT_ERROR (("Sleep State package elements are not both of type Number\n"));		status = AE_ERROR;	}	else {		/*		 *  Valid _Sx_ package size, type, and value		 */		*slp_typ_a = (u8) (obj_desc->package.elements[0])->number.value;		*slp_typ_b = (u8) (obj_desc->package.elements[1])->number.value;	}	acpi_cm_remove_reference (obj_desc);	return (status);}/******************************************************************************* * * FUNCTION:    Acpi_hw_register_bit_access * * PARAMETERS:  Read_write      - Either ACPI_READ or ACPI_WRITE. *              Use_lock        - Lock the hardware *              Register_id     - index of ACPI Register to access *              Value           - (only used on write) value to write to the *                                Register.  Shifted all the way right. * * RETURN:      Value written to or read from specified Register.  This value *              is shifted all the way right. * * DESCRIPTION: Generic ACPI Register read/write function. * ******************************************************************************/u32acpi_hw_register_bit_access (	NATIVE_UINT             read_write,	u8                      use_lock,	u32                     register_id,	...)                    /* Value (only used on write) */{	u32                     register_value = 0;	u32                     mask = 0;	u32                     value = 0;	if (read_write == ACPI_WRITE) {		va_list         marker;		va_start (marker, register_id);		value = va_arg (marker, u32);		va_end (marker);	}	if (ACPI_MTX_LOCK == use_lock) {		acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);	}	/*	 * Decode the Register ID	 *  Register id = Register block id | bit id	 *	 * Check bit id to fine locate Register offset.	 *  check Mask to determine Register offset, and then read-write.	 */	switch (REGISTER_BLOCK_ID(register_id))	{	case PM1_STS:		switch (register_id)		{		case TMR_STS:			mask = TMR_STS_MASK;			break;		case BM_STS:			mask = BM_STS_MASK;			break;		case GBL_STS:			mask = GBL_STS_MASK;			break;		case PWRBTN_STS:			mask = PWRBTN_STS_MASK;			break;		case SLPBTN_STS:			mask = SLPBTN_STS_MASK;			break;		case RTC_STS:			mask = RTC_STS_MASK;			break;		case WAK_STS:			mask = WAK_STS_MASK;			break;		default:			mask = 0;			break;		}		register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_STS);		if (read_write == ACPI_WRITE) {			/*			 * Status Registers are different from the rest.  Clear by			 * writing 1, writing 0 has no effect.  So, the only relevent			 * information is the single bit we're interested in, all			 * others should be written as 0 so they will be left			 * unchanged			 */			value <<= acpi_hw_get_bit_shift (mask);			value &= mask;			if (value) {				acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_STS, (u16) value);				register_value = 0;			}		}		break;	case PM1_EN:		switch (register_id)		{		case TMR_EN:			mask = TMR_EN_MASK;			break;		case GBL_EN:			mask = GBL_EN_MASK;			break;		case PWRBTN_EN:			mask = PWRBTN_EN_MASK;			break;		case SLPBTN_EN:			mask = SLPBTN_EN_MASK;			break;		case RTC_EN:			mask = RTC_EN_MASK;			break;		default:			mask = 0;			break;		}		register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_EN);		if (read_write == ACPI_WRITE) {			register_value &= ~mask;			value          <<= acpi_hw_get_bit_shift (mask);			value          &= mask;			register_value |= value;			acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, PM1_EN, (u16) register_value);		}		break;	case PM1_CONTROL:		switch (register_id)		{		case SCI_EN:			mask = SCI_EN_MASK;			break;		case BM_RLD:			mask = BM_RLD_MASK;			break;		case GBL_RLS:			mask = GBL_RLS_MASK;			break;		case SLP_TYPE_A:		case SLP_TYPE_B:			mask = SLP_TYPE_X_MASK;			break;		case SLP_EN:			mask = SLP_EN_MASK;			break;		default:			mask = 0;			break;		}		/*		 * Read the PM1 Control register.		 * Note that at this level, the fact that there are actually TWO		 * registers (A and B) and that B may not exist, are abstracted.		 */		register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_CONTROL);		if (read_write == ACPI_WRITE) {			register_value &= ~mask;			value          <<= acpi_hw_get_bit_shift (mask);			value          &= mask;			register_value |= value;			/*			 * SLP_TYPE_x Registers are written differently			 * than any other control Registers with			 * respect to A and B Registers.  The value			 * for A may be different than the value for B			 *			 * Therefore, pass the Register_id, not just generic PM1_CONTROL,			 * because we need to do different things. Yuck.			 */			acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,				register_id, (u16) register_value);		}		break;	case PM2_CONTROL:		switch (register_id)		{		case ARB_DIS:			mask = ARB_DIS_MASK;			break;		default:			mask = 0;			break;		}		register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM2_CONTROL);		if (read_write == ACPI_WRITE) {			register_value &= ~mask;			value          <<= acpi_hw_get_bit_shift (mask);			value          &= mask;			register_value |= value;			acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,					   PM2_CONTROL, (u8) (register_value));		}		break;	case PM_TIMER:		mask = TMR_VAL_MASK;		register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,				 PM_TIMER);		break;	case GPE1_EN_BLOCK:	case GPE1_STS_BLOCK:	case GPE0_EN_BLOCK:	case GPE0_STS_BLOCK:		/* Determine the bit to be accessed		 *		 *  (u32) Register_id:		 *      31      24       16       8        0		 *      +--------+--------+--------+--------+		 *      |  gpe_block_id   |  gpe_bit_number |		 *      +--------+--------+--------+--------+		 *		 *     gpe_block_id is one of GPE[01]_EN_BLOCK and GPE[01]_STS_BLOCK		 *     gpe_bit_number is relative from the gpe_block (0x00~0xFF)		 */		mask = REGISTER_BIT_ID(register_id); /* gpe_bit_number */		register_id = REGISTER_BLOCK_ID(register_id) | (mask >> 3);		mask = acpi_gbl_decode_to8bit [mask % 8];		/*		 * The base address of the GPE 0 Register Block		 * Plus 1/2 the length of the GPE 0 Register Block		 * The enable Register is the Register following the Status Register		 * and each Register is defined as 1/2 of the total Register Block		 */		/*		 * This sets the bit within Enable_bit that needs to be written to		 * the Register indicated in Mask to a 1, all others are 0		 */		/* Now get the current Enable Bits in the selected Reg */		register_value = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, register_id);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -