diff options
Diffstat (limited to 'drivers/acpi/acpica/hwvalid.c')
-rw-r--r-- | drivers/acpi/acpica/hwvalid.c | 85 |
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) | |||
218 | acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) | 219 | acpi_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) | |||
247 | acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) | 277 | acpi_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 | } |