--- linux-2.6.9/drivers/block/floppy.c.old 2004-11-04 16:13:41.000000000 +0100 +++ linux-2.6.9/drivers/block/floppy.c 2004-11-05 15:29:42.000000000 +0100 @@ -181,6 +181,12 @@ #include #include /* for invalidate_buffers() */ +#ifdef CONFIG_PNP +#include + +static int no_pnp_floppy; +#endif + #ifdef CONFIG_ACPI #include #include @@ -4157,6 +4163,9 @@ {"slow", NULL, &slow_floppy, 1, 0}, {"unexpected_interrupts", NULL, &print_unex, 1, 0}, {"no_unexpected_interrupts", NULL, &print_unex, 0, 0}, +#ifdef CONFIG_PNP + {"no_pnp", NULL, &no_pnp_floppy, 1, 0}, +#endif #ifdef CONFIG_ACPI {"no_acpi", NULL, &no_acpi_floppy, 1, 0}, #endif @@ -4232,10 +4241,7 @@ return get_disk(disks[drive]); } -#ifdef CONFIG_ACPI -static int acpi_floppy_registered; -static int acpi_floppies; - +#if defined(CONFIG_PNP) || defined(CONFIG_ACPI) struct region { unsigned int base; unsigned int size; @@ -4247,6 +4253,141 @@ unsigned int irq; unsigned int dma_channel; }; +#endif + +#ifdef CONFIG_PNP +static int pnp_floppy_registered; +static int pnp_floppies; + +static int pnp_floppy_probe(struct pnp_dev *dev, const struct pnp_device_id *did) +{ + struct floppy_resources fd; + unsigned int base, dcr; + + memset(&fd, 0, sizeof(fd)); + if (pnp_port_valid(dev,0) && + !(pnp_port_flags(dev,0) & IORESOURCE_DISABLED)) { + fd.io_region[0].base = pnp_port_start(dev,0); + fd.io_region[0].size = pnp_port_len(dev,0); + fd.nr_io_regions = 1; + } + + if (pnp_port_valid(dev,1) && + !(pnp_port_flags(dev,1) & IORESOURCE_DISABLED)) { + fd.io_region[1].base = pnp_port_start(dev,1); + fd.io_region[1].size = pnp_port_len(dev,1); + fd.nr_io_regions = 2; + } + + if (pnp_irq_valid(dev,0) && + !(pnp_irq_flags(dev,0) & IORESOURCE_DISABLED)) + fd.irq = pnp_irq(dev,0); + + if (pnp_dma_valid(dev,0) && + !(pnp_dma_flags(dev,0) & IORESOURCE_DISABLED)) + fd.dma_channel = pnp_dma(dev,0); + + printk("PNP: %s [%s] at I/O 0x%x-0x%x", + "Floppy Controller", pnp_dev_name(dev), + fd.io_region[0].base, + fd.io_region[0].base + fd.io_region[0].size - 1); + if (fd.nr_io_regions > 1) { + if (fd.io_region[1].size == 1) + printk(", 0x%x", fd.io_region[1].base); + else + printk(", 0x%x-0x%x", fd.io_region[1].base, + fd.io_region[1].base + fd.io_region[1].size - 1); + } + printk(" irq %d dma channel %d\n", fd.irq, fd.dma_channel); + + /* + * The most correct resource description is probably of the form + * 0x3f2-0x3f5, 0x3f7 + * Those are the only ports this driver actually uses. + * + * 0x3f0 and 0x3f1 were apparently used on PS/2 systems (though + * this driver doesn't touch them), and 0x3f6 is used by IDE. + * Some BIOS's erroneously include those ports, or omit 0x3f7, + * so we should also be able to handle the following: + * 0x3f0-0x3f5 + * 0x3f0-0x3f5, 0x3f7 + * 0x3f0-0x3f7 + * 0x3f2-0x3f7 + */ + base = fd.io_region[0].base & ~0x7; + dcr = base + 7; + +#define contains(region, port) ((region).base <= (port) && \ + (port) < (region).base + (region).size) + + if (!(contains(fd.io_region[0], dcr) || contains(fd.io_region[1], dcr))) { + printk(KERN_WARNING "PNP: [%s] doesn't declare FD_DCR; also claiming 0x%x\n", + pnp_dev_name(dev), dcr); + } + +#undef contains + + if (pnp_floppies == 0) { + FDC1 = base; + FLOPPY_IRQ = fd.irq; + FLOPPY_DMA = fd.dma_channel; + } else if (pnp_floppies == 1) { + FDC2 = base; + if (fd.irq != FLOPPY_IRQ || fd.dma_channel != FLOPPY_DMA) + printk(KERN_WARNING "%s: different IRQ/DMA info for [%s]; may not work\n", + DEVICE_NAME, pnp_dev_name(dev)); + } else { + printk(KERN_ERR "%s: only 2 controllers supported; [%s] ignored\n", + DEVICE_NAME, pnp_dev_name(dev)); + return -ENODEV; + } + + pnp_floppies++; + return 0; +} + +static struct pnp_device_id pnp_floppy_devids[] = { + { .id = "PNP0700", .driver_data = 0 }, + { .id = "", }, +}; + +MODULE_DEVICE_TABLE(pnp, pnp_floppy_devids); + +static struct pnp_driver pnp_floppy_driver = { + .name = "floppy", + .id_table = pnp_floppy_devids, + .probe = pnp_floppy_probe, +}; + +static int pnp_floppy_init(void) +{ + int err; + + if (no_pnp_floppy) { + printk("%s: PNP detection disabled\n", DEVICE_NAME); + return -ENODEV; + } + err = pnp_register_driver(&pnp_floppy_driver); + if (err >= 0) + pnp_floppy_registered = 1; + return err; +} + +static void pnp_floppy_exit(void) +{ + if (pnp_floppy_registered) { + pnp_unregister_driver(&pnp_floppy_driver); + pnp_floppy_registered = 0; + } +} +#else +static inline int pnp_floppy_init(void) { return -ENODEV; } +static inline void pnp_floppy_exit(void) { } +#endif + +#ifdef CONFIG_ACPI +static int acpi_floppy_registered; +static int acpi_floppies; static acpi_status acpi_floppy_resource(struct acpi_resource *res, void *data) { @@ -4401,6 +4542,11 @@ int i, unit, drive; int err, dr; + if (pnp_floppy_init() == 0) { + err = -ENODEV; + goto out_put_pnp; + } + if (acpi_floppy_init() == 0) { err = -ENODEV; goto out_put_acpi; @@ -4590,6 +4736,9 @@ del_timer(&motor_off_timer[dr]); put_disk(disks[dr]); } +out_put_pnp: + pnp_floppy_exit(); + return err; out_put_acpi: acpi_floppy_exit(); return err; @@ -4808,6 +4957,8 @@ /* eject disk, if any */ fd_eject(0); + pnp_floppy_exit(); + acpi_floppy_exit(); wait_for_completion(&device_release);