Date: Mon, 26 Jul 2004 19:23:40 -0700 From: Nate Lawson <nate@root.org> To: Tim Robbins <tjr@freebsd.org> Cc: Marcel Moolenaar <marcel@xcllnt.net> Subject: Re: Floppy disk drive no longer detected Message-ID: <4105BCAC.1000000@root.org> In-Reply-To: <20040726095929.GA30092@cat.robbins.dropbear.id.au> References: <20040726021326.GA23697@cat.robbins.dropbear.id.au> <20040726095929.GA30092@cat.robbins.dropbear.id.au>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------030909040700070302090300 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Tim Robbins wrote: > On Mon, Jul 26, 2004 at 12:13:26PM +1000, Tim Robbins wrote: > >>My floppy disk drive is no longer probed correctly by -CURRENT. I get the >>following message, but none about fd0 (and /dev/fd0 does not exist): >> >>fdc0: <floppy drive controller (FDE)> port 0x3f7,0x3f0-0x3f5 irq 6 drq 2 on acpi0 >> >>Previously it probed as: >> >>fdc0: <Enhanced floppy controller (i82077, NE72065 or clone)> port 0x3f7,0x3f0-0x3f5 irq 6 drq 2 on acpi0 >>fdc0: FIFO enabled, 8 bytes threshold >>fd0: <1440-KB 3.5" drive> on fdc0 drive 0 >> >>The ACPI DSDT for this system is available at: >>http://people.freebsd.org/~tjr/k8v.txt.bz2 > > > Ok, it looks like the FDC device should have a child device for each drive, > but my system's DSDT has none. Could we work around this in the driver by > not using _FDE/_FDI to probe unless the FDC device has at least 1 child with > an _FDI object, or should we add an entry to the quirks table for this > particular BIOS instead? Here's another version of the patch. It should fix _another_ problem I found with Tim's BIOS, namely that it uses a package instead of a buffer for _FDE. -Nate --------------030909040700070302090300 Content-Type: text/plain; name="fdc_acpi_fix.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="fdc_acpi_fix.diff" Index: fdc_acpi.c =================================================================== RCS file: /home/ncvs/src/sys/dev/fdc/fdc_acpi.c,v retrieving revision 1.1 diff -u -r1.1 fdc_acpi.c --- fdc_acpi.c 15 Jul 2004 16:38:07 -0000 1.1 +++ fdc_acpi.c 27 Jul 2004 02:02:39 -0000 @@ -42,21 +42,31 @@ static int fdc_acpi_probe(device_t dev); static int fdc_acpi_attach(device_t dev); +static int fdc_acpi_probe_children(device_t bus, device_t dev, + void *fde); static ACPI_STATUS fdc_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg); static void fdctl_wr_acpi(fdc_p fdc, u_int8_t v); -/* Parameters for the tape drive (5th device). */ -#define ACPI_TAPE_UNKNOWN 0 -#define ACPI_TAPE_PRESENT 1 -#define ACPI_TAPE_NEVER_PRESENT 2 +/* Maximum number of child devices of a controller (4 floppy + 1 tape.) */ +#define ACPI_FDC_MAXDEVS 5 + +/* + * 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 + * grossly incompatible with the spec since it says the first four devices + * are simple booleans. + */ +#define ACPI_FD_UNKNOWN 0 +#define ACPI_FD_PRESENT 1 +#define ACPI_FD_NEVER_PRESENT 2 /* Temporary buf length for evaluating _FDE and _FDI. */ #define ACPI_FDC_BUFLEN 1024 /* Context for walking FDC child devices. */ struct fdc_walk_ctx { - uint32_t fd_present[5]; + uint32_t fd_present[ACPI_FDC_MAXDEVS]; int index; device_t acpi_dev; device_t dev; @@ -88,12 +98,13 @@ static int fdc_acpi_attach(device_t dev) { - struct fdc_walk_ctx *ctx; struct fdc_data *sc; ACPI_BUFFER buf; device_t bus; - int error, ic_type; + int error, i, ic_type; + ACPI_OBJECT *obj, *pkg; ACPI_HANDLE h; + uint32_t *fde; /* Get our softc and use the same accessor as ISA. */ sc = device_get_softc(dev); @@ -145,29 +156,31 @@ */ bus = device_get_parent(dev); if (ACPI_SUCCESS(ACPI_EVALUATE_OBJECT(bus, dev, "_FDE", NULL, &buf))) { - /* Setup the context and walk all child devices. */ - ctx = malloc(sizeof(struct fdc_walk_ctx), M_TEMP, M_NOWAIT); - if (ctx == NULL) { - device_printf(dev, "no memory for walking children\n"); - goto out; + /* + * 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 = (uint32_t *)buf.Pointer; + pkg = (ACPI_OBJECT *)buf.Pointer; + if (pkg->Type == ACPI_TYPE_PACKAGE) { + fde = malloc(pkg->Package.Count * sizeof(uint32_t), + M_TEMP, M_NOWAIT | M_ZERO); + if (fde == NULL) { + error = ENOMEM; + 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; + } } - bcopy(buf.Pointer, ctx->fd_present, sizeof(ctx->fd_present)); - ctx->index = 0; - ctx->dev = dev; - ctx->acpi_dev = bus; - ACPI_SCAN_CHILDREN(ctx->acpi_dev, dev, 1, fdc_acpi_probe_child, - ctx); - free(ctx, M_TEMP); - - /* Attach any children found during the probe. */ - error = bus_generic_attach(dev); - if (error != 0) - goto out; - } else { + error = fdc_acpi_probe_children(bus, dev, fde); + if (pkg->Type == ACPI_TYPE_PACKAGE) + free(fde, M_TEMP); + } else error = fdc_hints_probe(dev); - if (error != 0) - goto out; - } out: if (buf.Pointer) @@ -178,6 +191,40 @@ return (error); } +static int +fdc_acpi_probe_children(device_t bus, device_t dev, void *fde) +{ + struct fdc_walk_ctx *ctx; + devclass_t fd_dc; + int i; + + /* Setup the context and walk all child devices. */ + ctx = malloc(sizeof(struct fdc_walk_ctx), M_TEMP, M_NOWAIT); + if (ctx == NULL) { + device_printf(dev, "no memory for walking children\n"); + return (ENOMEM); + } + bcopy(fde, ctx->fd_present, sizeof(ctx->fd_present)); + ctx->index = 0; + ctx->dev = dev; + ctx->acpi_dev = bus; + ACPI_SCAN_CHILDREN(ctx->acpi_dev, dev, 1, fdc_acpi_probe_child, + ctx); + + /* Add any devices not represented by an AML Device handle/node. */ + fd_dc = devclass_find("fd"); + for (i = 0; i < ACPI_FDC_MAXDEVS; i++) + if (ctx->fd_present[i] == ACPI_FD_PRESENT && + devclass_get_device(fd_dc, i) == NULL) { + if (fdc_add_child(dev, "fd", i) == NULL) + device_printf(dev, "fd add failed\n"); + } + free(ctx, M_TEMP); + + /* Attach any children found during the probe. */ + return (bus_generic_attach(dev)); +} + static ACPI_STATUS fdc_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg) { @@ -187,29 +234,38 @@ ACPI_OBJECT *pkg, *obj; ACPI_STATUS status; + ctx = (struct fdc_walk_ctx *)arg; + buf.Pointer = NULL; + /* * The first four ints are booleans that indicate whether fd0-3 are * present or not. The last is for a tape device, which we don't * bother supporting for now. */ - ctx = (struct fdc_walk_ctx *)arg; if (ctx->index > 3) return (AE_OK); + /* This device is not present, move on to the next. */ + if (ctx->fd_present[ctx->index] != ACPI_FD_PRESENT) + goto out; + + /* Create a device for the child with the given index. */ + child = fdc_add_child(ctx->dev, "fd", ctx->index); + if (child == NULL) + goto out; + *dev = child; + /* Get temporary buffer for _FDI probe. */ buf.Length = ACPI_FDC_BUFLEN; buf.Pointer = malloc(buf.Length, M_TEMP, M_NOWAIT | M_ZERO); if (buf.Pointer == NULL) goto out; - /* This device is not present, move on to the next. */ - if (ctx->fd_present[ctx->index] == 0) - goto out; - /* Evaluate _FDI to get drive type to pass to the child. */ status = ACPI_EVALUATE_OBJECT(ctx->acpi_dev, *dev, "_FDI", NULL, &buf); if (ACPI_FAILURE(status)) { - device_printf(ctx->dev, "_FDI not available - %#x\n", status); + if (status != AE_NOT_FOUND) + device_printf(ctx->dev, "_FDI failed - %#x\n", status); goto out; } pkg = (ACPI_OBJECT *)buf.Pointer; @@ -222,12 +278,6 @@ device_printf(ctx->dev, "invalid type object in _FDI\n"); goto out; } - - /* Create a device for the child with the given index and set ivars. */ - child = fdc_add_child(ctx->dev, "fd", ctx->index); - if (child == NULL) - goto out; - *dev = child; fdc_set_fdtype(child, obj->Integer.Value); out: --------------030909040700070302090300--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4105BCAC.1000000>