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