1
2/*******************************************************************************
3 *
4 * Module Name: hwregs - Read/write access functions for the various ACPI
5 *                       control and status registers.
6 *
7 ******************************************************************************/
8
9/*
10 * Copyright (C) 2000 - 2007, R. Byron Moore
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions, and the following disclaimer,
18 *    without modification.
19 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
20 *    substantially similar to the "NO WARRANTY" disclaimer below
21 *    ("Disclaimer") and any redistribution must be conditioned upon
22 *    including a substantially similar Disclaimer requirement for further
23 *    binary redistribution.
24 * 3. Neither the names of the above-listed copyright holders nor the names
25 *    of any contributors may be used to endorse or promote products derived
26 *    from this software without specific prior written permission.
27 *
28 * Alternatively, this software may be distributed under the terms of the
29 * GNU General Public License ("GPL") version 2 as published by the Free
30 * Software Foundation.
31 *
32 * NO WARRANTY
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
36 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
42 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 * POSSIBILITY OF SUCH DAMAGES.
44 */
45
46#include <acpi/acpi.h>
47#include <acpi/acnamesp.h>
48#include <acpi/acevents.h>
49
50#define _COMPONENT          ACPI_HARDWARE
51ACPI_MODULE_NAME("hwregs")
52
53/*******************************************************************************
54 *
55 * FUNCTION:    acpi_hw_clear_acpi_status
56 *
57 * PARAMETERS:  None
58 *
59 * RETURN:      None
60 *
61 * DESCRIPTION: Clears all fixed and general purpose status bits
62 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
63 *
64 ******************************************************************************/
65acpi_status acpi_hw_clear_acpi_status(void)
66{
67	acpi_status status;
68	acpi_cpu_flags lock_flags = 0;
69
70	ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
71
72	ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
73			  ACPI_BITMASK_ALL_FIXED_STATUS,
74			  (u16) acpi_gbl_FADT.xpm1a_event_block.address));
75
76	lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
77
78	status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
79					ACPI_REGISTER_PM1_STATUS,
80					ACPI_BITMASK_ALL_FIXED_STATUS);
81	if (ACPI_FAILURE(status)) {
82		goto unlock_and_exit;
83	}
84
85	/* Clear the fixed events */
86
87	if (acpi_gbl_FADT.xpm1b_event_block.address) {
88		status =
89		    acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
90					    &acpi_gbl_FADT.xpm1b_event_block);
91		if (ACPI_FAILURE(status)) {
92			goto unlock_and_exit;
93		}
94	}
95
96	/* Clear the GPE Bits in all GPE registers in all GPE blocks */
97
98	status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
99
100      unlock_and_exit:
101	acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
102	return_ACPI_STATUS(status);
103}
104
105/*******************************************************************************
106 *
107 * FUNCTION:    acpi_get_sleep_type_data
108 *
109 * PARAMETERS:  sleep_state         - Numeric sleep state
110 *              *sleep_type_a        - Where SLP_TYPa is returned
111 *              *sleep_type_b        - Where SLP_TYPb is returned
112 *
113 * RETURN:      Status - ACPI status
114 *
115 * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
116 *              state.
117 *
118 ******************************************************************************/
119
120acpi_status
121acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
122{
123	acpi_status status = AE_OK;
124	struct acpi_evaluate_info *info;
125
126	ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data);
127
128	/* Validate parameters */
129
130	if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) {
131		return_ACPI_STATUS(AE_BAD_PARAMETER);
132	}
133
134	/* Allocate the evaluation information block */
135
136	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
137	if (!info) {
138		return_ACPI_STATUS(AE_NO_MEMORY);
139	}
140
141	info->pathname =
142	    ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
143
144	/* Evaluate the namespace object containing the values for this state */
145
146	status = acpi_ns_evaluate(info);
147	if (ACPI_FAILURE(status)) {
148		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
149				  "%s while evaluating SleepState [%s]\n",
150				  acpi_format_exception(status),
151				  info->pathname));
152
153		goto cleanup;
154	}
155
156	/* Must have a return object */
157
158	if (!info->return_object) {
159		ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
160			    info->pathname));
161		status = AE_NOT_EXIST;
162	}
163
164	/* It must be of type Package */
165
166	else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) {
167		ACPI_ERROR((AE_INFO,
168			    "Sleep State return object is not a Package"));
169		status = AE_AML_OPERAND_TYPE;
170	}
171
172	/*
173	 * The package must have at least two elements. NOTE (March 2005): This
174	 * goes against the current ACPI spec which defines this object as a
175	 * package with one encoded DWORD element. However, existing practice
176	 * by BIOS vendors seems to be to have 2 or more elements, at least
177	 * one per sleep type (A/B).
178	 */
179	else if (info->return_object->package.count < 2) {
180		ACPI_ERROR((AE_INFO,
181			    "Sleep State return package does not have at least two elements"));
182		status = AE_AML_NO_OPERAND;
183	}
184
185	/* The first two elements must both be of type Integer */
186
187	else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0])
188		  != ACPI_TYPE_INTEGER) ||
189		 (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1])
190		  != ACPI_TYPE_INTEGER)) {
191		ACPI_ERROR((AE_INFO,
192			    "Sleep State return package elements are not both Integers (%s, %s)",
193			    acpi_ut_get_object_type_name(info->return_object->
194							 package.elements[0]),
195			    acpi_ut_get_object_type_name(info->return_object->
196							 package.elements[1])));
197		status = AE_AML_OPERAND_TYPE;
198	} else {
199		/* Valid _Sx_ package size, type, and value */
200
201		*sleep_type_a = (u8)
202		    (info->return_object->package.elements[0])->integer.value;
203		*sleep_type_b = (u8)
204		    (info->return_object->package.elements[1])->integer.value;
205	}
206
207	if (ACPI_FAILURE(status)) {
208		ACPI_EXCEPTION((AE_INFO, status,
209				"While evaluating SleepState [%s], bad Sleep object %p type %s",
210				info->pathname, info->return_object,
211				acpi_ut_get_object_type_name(info->
212							     return_object)));
213	}
214
215	acpi_ut_remove_reference(info->return_object);
216
217      cleanup:
218	ACPI_FREE(info);
219	return_ACPI_STATUS(status);
220}
221
222ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data)
223
224/*******************************************************************************
225 *
226 * FUNCTION:    acpi_hw_get_register_bit_mask
227 *
228 * PARAMETERS:  register_id         - Index of ACPI Register to access
229 *
230 * RETURN:      The bitmask to be used when accessing the register
231 *
232 * DESCRIPTION: Map register_id into a register bitmask.
233 *
234 ******************************************************************************/
235struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
236{
237	ACPI_FUNCTION_ENTRY();
238
239	if (register_id > ACPI_BITREG_MAX) {
240		ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X",
241			    register_id));
242		return (NULL);
243	}
244
245	return (&acpi_gbl_bit_register_info[register_id]);
246}
247
248/*******************************************************************************
249 *
250 * FUNCTION:    acpi_get_register
251 *
252 * PARAMETERS:  register_id     - ID of ACPI bit_register to access
253 *              return_value    - Value that was read from the register
254 *
255 * RETURN:      Status and the value read from specified Register. Value
256 *              returned is normalized to bit0 (is shifted all the way right)
257 *
258 * DESCRIPTION: ACPI bit_register read function.
259 *
260 ******************************************************************************/
261
262acpi_status acpi_get_register(u32 register_id, u32 * return_value)
263{
264	u32 register_value = 0;
265	struct acpi_bit_register_info *bit_reg_info;
266	acpi_status status;
267
268	ACPI_FUNCTION_TRACE(acpi_get_register);
269
270	/* Get the info structure corresponding to the requested ACPI Register */
271
272	bit_reg_info = acpi_hw_get_bit_register_info(register_id);
273	if (!bit_reg_info) {
274		return_ACPI_STATUS(AE_BAD_PARAMETER);
275	}
276
277	/* Read from the register */
278
279	status = acpi_hw_register_read(ACPI_MTX_LOCK,
280				       bit_reg_info->parent_register,
281				       &register_value);
282
283	if (ACPI_SUCCESS(status)) {
284
285		/* Normalize the value that was read */
286
287		register_value =
288		    ((register_value & bit_reg_info->access_bit_mask)
289		     >> bit_reg_info->bit_position);
290
291		*return_value = register_value;
292
293		ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read value %8.8X register %X\n",
294				  register_value,
295				  bit_reg_info->parent_register));
296	}
297
298	return_ACPI_STATUS(status);
299}
300
301ACPI_EXPORT_SYMBOL(acpi_get_register)
302
303/*******************************************************************************
304 *
305 * FUNCTION:    acpi_set_register
306 *
307 * PARAMETERS:  register_id     - ID of ACPI bit_register to access
308 *              Value           - (only used on write) value to write to the
309 *                                Register, NOT pre-normalized to the bit pos
310 *
311 * RETURN:      Status
312 *
313 * DESCRIPTION: ACPI Bit Register write function.
314 *
315 ******************************************************************************/
316acpi_status acpi_set_register(u32 register_id, u32 value)
317{
318	u32 register_value = 0;
319	struct acpi_bit_register_info *bit_reg_info;
320	acpi_status status;
321	acpi_cpu_flags lock_flags;
322
323	ACPI_FUNCTION_TRACE_U32(acpi_set_register, register_id);
324
325	/* Get the info structure corresponding to the requested ACPI Register */
326
327	bit_reg_info = acpi_hw_get_bit_register_info(register_id);
328	if (!bit_reg_info) {
329		ACPI_ERROR((AE_INFO, "Bad ACPI HW RegisterId: %X",
330			    register_id));
331		return_ACPI_STATUS(AE_BAD_PARAMETER);
332	}
333
334	lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
335
336	/* Always do a register read first so we can insert the new bits  */
337
338	status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
339				       bit_reg_info->parent_register,
340				       &register_value);
341	if (ACPI_FAILURE(status)) {
342		goto unlock_and_exit;
343	}
344
345	/*
346	 * Decode the Register ID
347	 * Register ID = [Register block ID] | [bit ID]
348	 *
349	 * Check bit ID to fine locate Register offset.
350	 * Check Mask to determine Register offset, and then read-write.
351	 */
352	switch (bit_reg_info->parent_register) {
353	case ACPI_REGISTER_PM1_STATUS:
354
355		/*
356		 * Status Registers are different from the rest. Clear by
357		 * writing 1, and writing 0 has no effect. So, the only relevant
358		 * information is the single bit we're interested in, all others should
359		 * be written as 0 so they will be left unchanged.
360		 */
361		value = ACPI_REGISTER_PREPARE_BITS(value,
362						   bit_reg_info->bit_position,
363						   bit_reg_info->
364						   access_bit_mask);
365		if (value) {
366			status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
367							ACPI_REGISTER_PM1_STATUS,
368							(u16) value);
369			register_value = 0;
370		}
371		break;
372
373	case ACPI_REGISTER_PM1_ENABLE:
374
375		ACPI_REGISTER_INSERT_VALUE(register_value,
376					   bit_reg_info->bit_position,
377					   bit_reg_info->access_bit_mask,
378					   value);
379
380		status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
381						ACPI_REGISTER_PM1_ENABLE,
382						(u16) register_value);
383		break;
384
385	case ACPI_REGISTER_PM1_CONTROL:
386
387		/*
388		 * Write the PM1 Control register.
389		 * Note that at this level, the fact that there are actually TWO
390		 * registers (A and B - and B may not exist) is abstracted.
391		 */
392		ACPI_DEBUG_PRINT((ACPI_DB_IO, "PM1 control: Read %X\n",
393				  register_value));
394
395		ACPI_REGISTER_INSERT_VALUE(register_value,
396					   bit_reg_info->bit_position,
397					   bit_reg_info->access_bit_mask,
398					   value);
399
400		status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
401						ACPI_REGISTER_PM1_CONTROL,
402						(u16) register_value);
403		break;
404
405	case ACPI_REGISTER_PM2_CONTROL:
406
407		status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
408					       ACPI_REGISTER_PM2_CONTROL,
409					       &register_value);
410		if (ACPI_FAILURE(status)) {
411			goto unlock_and_exit;
412		}
413
414		ACPI_DEBUG_PRINT((ACPI_DB_IO,
415				  "PM2 control: Read %X from %8.8X%8.8X\n",
416				  register_value,
417				  ACPI_FORMAT_UINT64(acpi_gbl_FADT.
418						     xpm2_control_block.
419						     address)));
420
421		ACPI_REGISTER_INSERT_VALUE(register_value,
422					   bit_reg_info->bit_position,
423					   bit_reg_info->access_bit_mask,
424					   value);
425
426		ACPI_DEBUG_PRINT((ACPI_DB_IO,
427				  "About to write %4.4X to %8.8X%8.8X\n",
428				  register_value,
429				  ACPI_FORMAT_UINT64(acpi_gbl_FADT.
430						     xpm2_control_block.
431						     address)));
432
433		status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
434						ACPI_REGISTER_PM2_CONTROL,
435						(u8) (register_value));
436		break;
437
438	default:
439		break;
440	}
441
442      unlock_and_exit:
443
444	acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
445
446	/* Normalize the value that was read */
447
448	ACPI_DEBUG_EXEC(register_value =
449			((register_value & bit_reg_info->access_bit_mask) >>
450			 bit_reg_info->bit_position));
451
452	ACPI_DEBUG_PRINT((ACPI_DB_IO,
453			  "Set bits: %8.8X actual %8.8X register %X\n", value,
454			  register_value, bit_reg_info->parent_register));
455	return_ACPI_STATUS(status);
456}
457
458ACPI_EXPORT_SYMBOL(acpi_set_register)
459
460/******************************************************************************
461 *
462 * FUNCTION:    acpi_hw_register_read
463 *
464 * PARAMETERS:  use_lock            - Lock hardware? True/False
465 *              register_id         - ACPI Register ID
466 *              return_value        - Where the register value is returned
467 *
468 * RETURN:      Status and the value read.
469 *
470 * DESCRIPTION: Read from the specified ACPI register
471 *
472 ******************************************************************************/
473acpi_status
474acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
475{
476	u32 value1 = 0;
477	u32 value2 = 0;
478	acpi_status status;
479	acpi_cpu_flags lock_flags = 0;
480
481	ACPI_FUNCTION_TRACE(hw_register_read);
482
483	if (ACPI_MTX_LOCK == use_lock) {
484		lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
485	}
486
487	switch (register_id) {
488	case ACPI_REGISTER_PM1_STATUS:	/* 16-bit access */
489
490		status =
491		    acpi_hw_low_level_read(16, &value1,
492					   &acpi_gbl_FADT.xpm1a_event_block);
493		if (ACPI_FAILURE(status)) {
494			goto unlock_and_exit;
495		}
496
497		/* PM1B is optional */
498
499		status =
500		    acpi_hw_low_level_read(16, &value2,
501					   &acpi_gbl_FADT.xpm1b_event_block);
502		value1 |= value2;
503		break;
504
505	case ACPI_REGISTER_PM1_ENABLE:	/* 16-bit access */
506
507		status =
508		    acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable);
509		if (ACPI_FAILURE(status)) {
510			goto unlock_and_exit;
511		}
512
513		/* PM1B is optional */
514
515		status =
516		    acpi_hw_low_level_read(16, &value2, &acpi_gbl_xpm1b_enable);
517		value1 |= value2;
518		break;
519
520	case ACPI_REGISTER_PM1_CONTROL:	/* 16-bit access */
521
522		status =
523		    acpi_hw_low_level_read(16, &value1,
524					   &acpi_gbl_FADT.xpm1a_control_block);
525		if (ACPI_FAILURE(status)) {
526			goto unlock_and_exit;
527		}
528
529		status =
530		    acpi_hw_low_level_read(16, &value2,
531					   &acpi_gbl_FADT.xpm1b_control_block);
532		value1 |= value2;
533		break;
534
535	case ACPI_REGISTER_PM2_CONTROL:	/* 8-bit access */
536
537		status =
538		    acpi_hw_low_level_read(8, &value1,
539					   &acpi_gbl_FADT.xpm2_control_block);
540		break;
541
542	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
543
544		status =
545		    acpi_hw_low_level_read(32, &value1,
546					   &acpi_gbl_FADT.xpm_timer_block);
547		break;
548
549	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
550
551		status =
552		    acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
553		break;
554
555	default:
556		ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id));
557		status = AE_BAD_PARAMETER;
558		break;
559	}
560
561      unlock_and_exit:
562	if (ACPI_MTX_LOCK == use_lock) {
563		acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
564	}
565
566	if (ACPI_SUCCESS(status)) {
567		*return_value = value1;
568	}
569
570	return_ACPI_STATUS(status);
571}
572
573/******************************************************************************
574 *
575 * FUNCTION:    acpi_hw_register_write
576 *
577 * PARAMETERS:  use_lock            - Lock hardware? True/False
578 *              register_id         - ACPI Register ID
579 *              Value               - The value to write
580 *
581 * RETURN:      Status
582 *
583 * DESCRIPTION: Write to the specified ACPI register
584 *
585 * NOTE: In accordance with the ACPI specification, this function automatically
586 * preserves the value of the following bits, meaning that these bits cannot be
587 * changed via this interface:
588 *
589 * PM1_CONTROL[0] = SCI_EN
590 * PM1_CONTROL[9]
591 * PM1_STATUS[11]
592 *
593 * ACPI References:
594 * 1) Hardware Ignored Bits: When software writes to a register with ignored
595 *      bit fields, it preserves the ignored bit fields
596 * 2) SCI_EN: OSPM always preserves this bit position
597 *
598 ******************************************************************************/
599
600acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
601{
602	acpi_status status;
603	acpi_cpu_flags lock_flags = 0;
604	u32 read_value;
605
606	ACPI_FUNCTION_TRACE(hw_register_write);
607
608	if (ACPI_MTX_LOCK == use_lock) {
609		lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
610	}
611
612	switch (register_id) {
613	case ACPI_REGISTER_PM1_STATUS:	/* 16-bit access */
614
615		/* Perform a read first to preserve certain bits (per ACPI spec) */
616
617		status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
618					       ACPI_REGISTER_PM1_STATUS,
619					       &read_value);
620		if (ACPI_FAILURE(status)) {
621			goto unlock_and_exit;
622		}
623
624		/* Insert the bits to be preserved */
625
626		ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
627				 read_value);
628
629		/* Now we can write the data */
630
631		status =
632		    acpi_hw_low_level_write(16, value,
633					    &acpi_gbl_FADT.xpm1a_event_block);
634		if (ACPI_FAILURE(status)) {
635			goto unlock_and_exit;
636		}
637
638		/* PM1B is optional */
639
640		status =
641		    acpi_hw_low_level_write(16, value,
642					    &acpi_gbl_FADT.xpm1b_event_block);
643		break;
644
645	case ACPI_REGISTER_PM1_ENABLE:	/* 16-bit access */
646
647		status =
648		    acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable);
649		if (ACPI_FAILURE(status)) {
650			goto unlock_and_exit;
651		}
652
653		/* PM1B is optional */
654
655		status =
656		    acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1b_enable);
657		break;
658
659	case ACPI_REGISTER_PM1_CONTROL:	/* 16-bit access */
660
661		/*
662		 * Perform a read first to preserve certain bits (per ACPI spec)
663		 */
664		status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
665					       ACPI_REGISTER_PM1_CONTROL,
666					       &read_value);
667		if (ACPI_FAILURE(status)) {
668			goto unlock_and_exit;
669		}
670
671		/* Insert the bits to be preserved */
672
673		ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
674				 read_value);
675
676		/* Now we can write the data */
677
678		status =
679		    acpi_hw_low_level_write(16, value,
680					    &acpi_gbl_FADT.xpm1a_control_block);
681		if (ACPI_FAILURE(status)) {
682			goto unlock_and_exit;
683		}
684
685		status =
686		    acpi_hw_low_level_write(16, value,
687					    &acpi_gbl_FADT.xpm1b_control_block);
688		break;
689
690	case ACPI_REGISTER_PM1A_CONTROL:	/* 16-bit access */
691
692		status =
693		    acpi_hw_low_level_write(16, value,
694					    &acpi_gbl_FADT.xpm1a_control_block);
695		break;
696
697	case ACPI_REGISTER_PM1B_CONTROL:	/* 16-bit access */
698
699		status =
700		    acpi_hw_low_level_write(16, value,
701					    &acpi_gbl_FADT.xpm1b_control_block);
702		break;
703
704	case ACPI_REGISTER_PM2_CONTROL:	/* 8-bit access */
705
706		status =
707		    acpi_hw_low_level_write(8, value,
708					    &acpi_gbl_FADT.xpm2_control_block);
709		break;
710
711	case ACPI_REGISTER_PM_TIMER:	/* 32-bit access */
712
713		status =
714		    acpi_hw_low_level_write(32, value,
715					    &acpi_gbl_FADT.xpm_timer_block);
716		break;
717
718	case ACPI_REGISTER_SMI_COMMAND_BLOCK:	/* 8-bit access */
719
720		/* SMI_CMD is currently always in IO space */
721
722		status =
723		    acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
724		break;
725
726	default:
727		status = AE_BAD_PARAMETER;
728		break;
729	}
730
731      unlock_and_exit:
732	if (ACPI_MTX_LOCK == use_lock) {
733		acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
734	}
735
736	return_ACPI_STATUS(status);
737}
738
739/******************************************************************************
740 *
741 * FUNCTION:    acpi_hw_low_level_read
742 *
743 * PARAMETERS:  Width               - 8, 16, or 32
744 *              Value               - Where the value is returned
745 *              Reg                 - GAS register structure
746 *
747 * RETURN:      Status
748 *
749 * DESCRIPTION: Read from either memory or IO space.
750 *
751 ******************************************************************************/
752
753acpi_status
754acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
755{
756	u64 address;
757	acpi_status status;
758
759	ACPI_FUNCTION_NAME(hw_low_level_read);
760
761	/*
762	 * Must have a valid pointer to a GAS structure, and
763	 * a non-zero address within. However, don't return an error
764	 * because the PM1A/B code must not fail if B isn't present.
765	 */
766	if (!reg) {
767		return (AE_OK);
768	}
769
770	/* Get a local copy of the address. Handles possible alignment issues */
771
772	ACPI_MOVE_64_TO_64(&address, &reg->address);
773	if (!address) {
774		return (AE_OK);
775	}
776	*value = 0;
777
778	/*
779	 * Two address spaces supported: Memory or IO.
780	 * PCI_Config is not supported here because the GAS struct is insufficient
781	 */
782	switch (reg->space_id) {
783	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
784
785		status = acpi_os_read_memory((acpi_physical_address) address,
786					     value, width);
787		break;
788
789	case ACPI_ADR_SPACE_SYSTEM_IO:
790
791		status =
792		    acpi_os_read_port((acpi_io_address) address, value, width);
793		break;
794
795	default:
796		ACPI_ERROR((AE_INFO,
797			    "Unsupported address space: %X", reg->space_id));
798		return (AE_BAD_PARAMETER);
799	}
800
801	ACPI_DEBUG_PRINT((ACPI_DB_IO,
802			  "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
803			  *value, width, ACPI_FORMAT_UINT64(address),
804			  acpi_ut_get_region_name(reg->space_id)));
805
806	return (status);
807}
808
809/******************************************************************************
810 *
811 * FUNCTION:    acpi_hw_low_level_write
812 *
813 * PARAMETERS:  Width               - 8, 16, or 32
814 *              Value               - To be written
815 *              Reg                 - GAS register structure
816 *
817 * RETURN:      Status
818 *
819 * DESCRIPTION: Write to either memory or IO space.
820 *
821 ******************************************************************************/
822
823acpi_status
824acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
825{
826	u64 address;
827	acpi_status status;
828
829	ACPI_FUNCTION_NAME(hw_low_level_write);
830
831	/*
832	 * Must have a valid pointer to a GAS structure, and
833	 * a non-zero address within. However, don't return an error
834	 * because the PM1A/B code must not fail if B isn't present.
835	 */
836	if (!reg) {
837		return (AE_OK);
838	}
839
840	/* Get a local copy of the address. Handles possible alignment issues */
841
842	ACPI_MOVE_64_TO_64(&address, &reg->address);
843	if (!address) {
844		return (AE_OK);
845	}
846
847	/*
848	 * Two address spaces supported: Memory or IO.
849	 * PCI_Config is not supported here because the GAS struct is insufficient
850	 */
851	switch (reg->space_id) {
852	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
853
854		status = acpi_os_write_memory((acpi_physical_address) address,
855					      value, width);
856		break;
857
858	case ACPI_ADR_SPACE_SYSTEM_IO:
859
860		status = acpi_os_write_port((acpi_io_address) address, value,
861					    width);
862		break;
863
864	default:
865		ACPI_ERROR((AE_INFO,
866			    "Unsupported address space: %X", reg->space_id));
867		return (AE_BAD_PARAMETER);
868	}
869
870	ACPI_DEBUG_PRINT((ACPI_DB_IO,
871			  "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
872			  value, width, ACPI_FORMAT_UINT64(address),
873			  acpi_ut_get_region_name(reg->space_id)));
874
875	return (status);
876}
877