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

📄 hwregs.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 2 页
字号:

/*******************************************************************************
 *
 * Module Name: hwregs - Read/write access functions for the various ACPI
 *                       control and status registers.
 *              $Revision: 1.1 $
 *
 ******************************************************************************/

/*
 *  Copyright (C) 2000, 2001 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>

#define _COMPONENT          ACPI_HARDWARE
	 MODULE_NAME         ("hwregs")


/* This matches the #defines in actypes.h. */

NATIVE_CHAR                 *sleep_state_table[] = {"\\_S0_","\\_S1_","\\_S2_","\\_S3_",
			  "\\_S4_","\\_S5_","\\_S4_b"};


/*******************************************************************************
 *
 * 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.
 *
 ******************************************************************************/

u32
acpi_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
 *
 ******************************************************************************/

void
acpi_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_STATUS
acpi_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
	 */

	/* Even though Acpi_evaluate_object resolves package references,
	 * Ns_evaluate dpesn't. So, we do it here.
	 */
	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_INTEGER) ||
			 ((obj_desc->package.elements[1])->common.type !=
				ACPI_TYPE_INTEGER)) {
		/* 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])->integer.value;

		*slp_typ_b = (u8) (obj_desc->package.elements[1])->integer.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.
 *
 ******************************************************************************/

u32
acpi_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

⌨️ 快捷键说明

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