1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-18 15:30:21 +00:00

Handle _FDE results of 5 bytes (vs. 5 uint32_t's). BIOS vendors find yet

another way to misinterpret the spec.  Also, always fall back to the hints
probe on any attach failure, not just when _FDE fails.

Thanks to imp and scottl for finding this.

Tested by:	rwatson (minimally)
MFC after:	5 days
This commit is contained in:
Nate Lawson 2004-09-17 04:14:38 +00:00
parent 6874bcf242
commit a3f51d1971
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=135355

View File

@ -49,6 +49,9 @@ static ACPI_STATUS fdc_acpi_probe_child(ACPI_HANDLE h, device_t *dev,
/* Maximum number of child devices of a controller (4 floppy + 1 tape.) */
#define ACPI_FDC_MAXDEVS 5
/* Standard size of buffer returned by the _FDE method. */
#define ACPI_FDC_FDE_LEN (ACPI_FDC_MAXDEVS * sizeof(uint32_t))
/*
* Parameters for the tape drive (5th device). Some BIOS authors use this
* for all drives, not just the tape drive (e.g., ASUS K8V). This isn't
@ -93,10 +96,10 @@ fdc_acpi_attach(device_t dev)
struct fdc_data *sc;
ACPI_BUFFER buf;
device_t bus;
int error, i;
int error, fde_count, i;
ACPI_OBJECT *obj, *pkg;
ACPI_HANDLE h;
uint32_t *fde;
uint32_t fde[ACPI_FDC_MAXDEVS];
/* Get our softc and use the same accessor as ISA. */
sc = device_get_softc(dev);
@ -126,48 +129,62 @@ fdc_acpi_attach(device_t dev)
* this fails, fall back to the ISA hints-based probe method.
*/
bus = device_get_parent(dev);
if (ACPI_SUCCESS(ACPI_EVALUATE_OBJECT(bus, dev, "_FDE", NULL, &buf))) {
obj = pkg = (ACPI_OBJECT *)buf.Pointer;
switch (obj->Type) {
case ACPI_TYPE_BUFFER:
/*
* The spec says _FDE should be a buffer of five
* 32-bit integers.
*/
fde = (uint32_t *)obj->Buffer.Pointer;
if (obj->Buffer.Length < 20) {
device_printf(dev, "_FDE too small\n");
goto out;
}
if (ACPI_FAILURE(ACPI_EVALUATE_OBJECT(bus, dev, "_FDE", NULL, &buf))) {
error = ENXIO;
goto out;
}
/* Parse the output of _FDE in various ways. */
obj = pkg = (ACPI_OBJECT *)buf.Pointer;
switch (obj->Type) {
case ACPI_TYPE_BUFFER:
/*
* The spec says _FDE should be a buffer of five 32-bit
* integers. In violation of the spec, some systems use
* five bytes instead.
*/
switch (obj->Buffer.Length) {
case ACPI_FDC_FDE_LEN:
bcopy(obj->Buffer.Pointer, fde, ACPI_FDC_FDE_LEN);
break;
case ACPI_TYPE_PACKAGE:
/*
* In violation of the spec, systems including the ASUS
* K8V return a package of five integers instead of a
* buffer of five 32-bit integers.
*/
fde = malloc(pkg->Package.Count * sizeof(uint32_t),
M_TEMP, M_NOWAIT | M_ZERO);
if (fde == NULL) {
goto out;
}
for (i = 0; i < pkg->Package.Count; i++) {
obj = &pkg->Package.Elements[i];
if (obj->Type == ACPI_TYPE_INTEGER)
fde[i] = (uint32_t)obj->Integer.Value;
}
case ACPI_FDC_MAXDEVS:
for (i = 0; i < ACPI_FDC_MAXDEVS; i++)
fde[i] = ((uint8_t *)obj->Buffer.Pointer)[i];
break;
default:
device_printf(dev, "invalid _FDE type %d\n", obj->Type);
device_printf(dev, "_FDE wrong length: %d\n",
obj->Buffer.Length);
error = ENXIO;
goto out;
}
error = fdc_acpi_probe_children(bus, dev, fde);
if (pkg->Type == ACPI_TYPE_PACKAGE)
free(fde, M_TEMP);
} else
error = fdc_hints_probe(dev);
break;
case ACPI_TYPE_PACKAGE:
/*
* In violation of the spec, systems including the ASUS
* K8V return a package of five integers instead of a
* buffer of five 32-bit integers.
*/
fde_count = min(ACPI_FDC_MAXDEVS, pkg->Package.Count);
for (i = 0; i < fde_count; i++) {
obj = &pkg->Package.Elements[i];
if (obj->Type == ACPI_TYPE_INTEGER)
fde[i] = (uint32_t)obj->Integer.Value;
}
break;
default:
device_printf(dev, "invalid _FDE type %d\n", obj->Type);
error = ENXIO;
goto out;
}
/* Add fd child devices as specified. */
error = fdc_acpi_probe_children(bus, dev, fde);
out:
/* If there was a problem, fall back to the hints-based probe. */
if (error)
error = fdc_hints_probe(dev);
if (buf.Pointer)
free(buf.Pointer, M_TEMP);
if (error != 0)