aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/hwvalid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/hwvalid.c')
-rw-r--r--drivers/acpi/acpica/hwvalid.c85
1 files changed, 71 insertions, 14 deletions
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index bd3c937b0ac0..ec33f270c5b7 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -152,7 +152,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
152 ACPI_ERROR((AE_INFO, 152 ACPI_ERROR((AE_INFO,
153 "Illegal I/O port address/length above 64K: 0x%p/%X", 153 "Illegal I/O port address/length above 64K: 0x%p/%X",
154 ACPI_CAST_PTR(void, address), byte_width)); 154 ACPI_CAST_PTR(void, address), byte_width));
155 return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); 155 return_ACPI_STATUS(AE_LIMIT);
156 } 156 }
157 157
158 /* Exit if requested address is not within the protected port table */ 158 /* Exit if requested address is not within the protected port table */
@@ -179,11 +179,12 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
179 /* Port illegality may depend on the _OSI calls made by the BIOS */ 179 /* Port illegality may depend on the _OSI calls made by the BIOS */
180 180
181 if (acpi_gbl_osi_data >= port_info->osi_dependency) { 181 if (acpi_gbl_osi_data >= port_info->osi_dependency) {
182 ACPI_ERROR((AE_INFO, 182 ACPI_DEBUG_PRINT((ACPI_DB_IO,
183 "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", 183 "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)",
184 ACPI_CAST_PTR(void, address), 184 ACPI_CAST_PTR(void, address),
185 byte_width, port_info->name, 185 byte_width, port_info->name,
186 port_info->start, port_info->end)); 186 port_info->start,
187 port_info->end));
187 188
188 return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); 189 return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
189 } 190 }
@@ -207,7 +208,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
207 * Value Where value is placed 208 * Value Where value is placed
208 * Width Number of bits 209 * Width Number of bits
209 * 210 *
210 * RETURN: Value read from port 211 * RETURN: Status and value read from port
211 * 212 *
212 * DESCRIPTION: Read data from an I/O port or register. This is a front-end 213 * DESCRIPTION: Read data from an I/O port or register. This is a front-end
213 * to acpi_os_read_port that performs validation on both the port 214 * to acpi_os_read_port that performs validation on both the port
@@ -218,14 +219,43 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
218acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) 219acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
219{ 220{
220 acpi_status status; 221 acpi_status status;
222 u32 one_byte;
223 u32 i;
224
225 /* Validate the entire request and perform the I/O */
221 226
222 status = acpi_hw_validate_io_request(address, width); 227 status = acpi_hw_validate_io_request(address, width);
223 if (ACPI_FAILURE(status)) { 228 if (ACPI_SUCCESS(status)) {
229 status = acpi_os_read_port(address, value, width);
224 return status; 230 return status;
225 } 231 }
226 232
227 status = acpi_os_read_port(address, value, width); 233 if (status != AE_AML_ILLEGAL_ADDRESS) {
228 return status; 234 return status;
235 }
236
237 /*
238 * There has been a protection violation within the request. Fall
239 * back to byte granularity port I/O and ignore the failing bytes.
240 * This provides Windows compatibility.
241 */
242 for (i = 0, *value = 0; i < width; i += 8) {
243
244 /* Validate and read one byte */
245
246 if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
247 status = acpi_os_read_port(address, &one_byte, 8);
248 if (ACPI_FAILURE(status)) {
249 return status;
250 }
251
252 *value |= (one_byte << i);
253 }
254
255 address++;
256 }
257
258 return AE_OK;
229} 259}
230 260
231/****************************************************************************** 261/******************************************************************************
@@ -236,7 +266,7 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
236 * Value Value to write 266 * Value Value to write
237 * Width Number of bits 267 * Width Number of bits
238 * 268 *
239 * RETURN: None 269 * RETURN: Status
240 * 270 *
241 * DESCRIPTION: Write data to an I/O port or register. This is a front-end 271 * DESCRIPTION: Write data to an I/O port or register. This is a front-end
242 * to acpi_os_write_port that performs validation on both the port 272 * to acpi_os_write_port that performs validation on both the port
@@ -247,12 +277,39 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
247acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) 277acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
248{ 278{
249 acpi_status status; 279 acpi_status status;
280 u32 i;
281
282 /* Validate the entire request and perform the I/O */
250 283
251 status = acpi_hw_validate_io_request(address, width); 284 status = acpi_hw_validate_io_request(address, width);
252 if (ACPI_FAILURE(status)) { 285 if (ACPI_SUCCESS(status)) {
286 status = acpi_os_write_port(address, value, width);
253 return status; 287 return status;
254 } 288 }
255 289
256 status = acpi_os_write_port(address, value, width); 290 if (status != AE_AML_ILLEGAL_ADDRESS) {
257 return status; 291 return status;
292 }
293
294 /*
295 * There has been a protection violation within the request. Fall
296 * back to byte granularity port I/O and ignore the failing bytes.
297 * This provides Windows compatibility.
298 */
299 for (i = 0; i < width; i += 8) {
300
301 /* Validate and write one byte */
302
303 if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
304 status =
305 acpi_os_write_port(address, (value >> i) & 0xFF, 8);
306 if (ACPI_FAILURE(status)) {
307 return status;
308 }
309 }
310
311 address++;
312 }
313
314 return AE_OK;
258} 315}