fix Magicbox for .21 and convert to the new structure
authorImre Kaloz <kaloz@openwrt.org>
Thu, 24 May 2007 12:44:44 +0000 (12:44 +0000)
committerImre Kaloz <kaloz@openwrt.org>
Thu, 24 May 2007 12:44:44 +0000 (12:44 +0000)
SVN-Revision: 7328

target/linux/generic-2.6/config-template
target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.c [new file with mode: 0644]
target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.h [new file with mode: 0644]
target/linux/magicbox-2.6/files/drivers/ide/ppc/magicbox_ide.c [new file with mode: 0644]
target/linux/magicbox-2.6/files/drivers/mtd/maps/magicmap.c [new file with mode: 0644]
target/linux/magicbox-2.6/patches/001-magicbox_support.patch
target/linux/magicbox-2.6/patches/002-flash_map.patch
target/linux/magicbox-2.6/patches/100-cf_slot.patch

index 1c1d57077da6834ed8455784235d05940b567781..d06096ee2d9e56ef7766e3d3fa8333ada25db0a4 100644 (file)
@@ -293,6 +293,7 @@ CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_FAT_FS=m
 # CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
 # CONFIG_FDDI is not set
 # CONFIG_FEALNX is not set
 CONFIG_FIB_RULES=y
@@ -339,6 +340,7 @@ CONFIG_HOTPLUG=y
 # CONFIG_HWMON is not set
 # CONFIG_HWMON_VID is not set
 # CONFIG_HZ_1000 is not set
+# CONFIG_HZ_300 is not set
 # CONFIG_I2C_ALGOPCA is not set
 # CONFIG_I2C_ALGOPCF is not set
 # CONFIG_I2C_ALI1535 is not set
@@ -623,6 +625,7 @@ CONFIG_LOCKD_V4=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_LSF is not set
 # CONFIG_LXT_PHY is not set
+# CONFIG_MAC_EMUMOUSEBTN is not set
 CONFIG_MAC_PARTITION=y
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_MARKEINS is not set
@@ -1107,6 +1110,7 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_UARTLITE is not set
 # CONFIG_SERIO is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_SGI_PARTITION is not set
diff --git a/target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.c b/target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.c
new file mode 100644 (file)
index 0000000..470fbc4
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Support for IBM PPC 405EP-based MagicBox board 
+ * Copyright (C) 2006  Karol Lewandowski
+ *
+ * Heavily based on bubinga.c
+ *
+ * Author: SAW (IBM), derived from walnut.c.
+ *         Maintained by MontaVista Software <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Softare Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/kgdb.h>
+#include <asm/ocp.h>
+#include <asm/ibm_ocp_pci.h>
+
+#include <platforms/4xx/ibm405ep.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+extern bd_t __res;
+
+/* Some IRQs unique to board
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       static char pci_irq_table[][4] =
+           /*
+            *      PCI IDSEL/INTPIN->INTLINE
+            *      A       B       C       D
+            */
+       {
+               {28, 28, 28, 28},       /* IDSEL 1 - PCI slot 1 */
+               {29, 29, 29, 29},       /* IDSEL 2 - PCI slot 2 */
+               {30, 30, 30, 30},       /* IDSEL 3 - PCI slot 3 */
+               {31, 31, 31, 31},       /* IDSEL 4 - PCI slot 4 */
+       };
+
+       const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+       return PCI_IRQ_TABLE_LOOKUP;
+};
+
+
+/* The serial clock for the chip is an internal clock determined by
+ * different clock speeds/dividers.
+ * Calculate the proper input baud rate and setup the serial driver.
+ */
+static void __init
+magicbox_early_serial_map(void)
+{
+       u32 uart_div;
+       int uart_clock;
+       struct uart_port port;
+
+         /* Calculate the serial clock input frequency
+          *
+          * The base baud is the PLL OUTA (provided in the board info
+          * structure) divided by the external UART Divisor, divided
+          * by 16.
+          */
+       uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV);
+       uart_clock = __res.bi_procfreq / uart_div;
+
+       /* Setup serial port access */
+       memset(&port, 0, sizeof(port));
+       port.membase = (void*)ACTING_UART0_IO_BASE;
+       port.irq = ACTING_UART0_INT;
+       port.uartclk = uart_clock;
+       port.regshift = 0;
+       port.iotype = SERIAL_IO_MEM;
+       port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+       port.line = 0;
+
+       if (early_serial_setup(&port) != 0) {
+               printk("Early serial init of port 0 failed\n");
+       }
+
+       port.membase = (void*)ACTING_UART1_IO_BASE;
+       port.irq = ACTING_UART1_INT;
+       port.line = 1;
+
+       if (early_serial_setup(&port) != 0) {
+               printk("Early serial init of port 1 failed\n");
+       }
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+       unsigned int bar_response, bar;
+       /*
+        * Expected PCI mapping:
+        *
+        *  PLB addr             PCI memory addr
+        *  ---------------------       ---------------------
+        *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
+        *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
+        *
+        *  PLB addr             PCI io addr
+        *  ---------------------       ---------------------
+        *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
+        *
+        * The following code is simplified by assuming that the bootrom
+        * has been well behaved in following this mapping.
+        */
+
+#ifdef DEBUG
+       int i;
+
+       printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+       printk("PCI bridge regs before fixup \n");
+       for (i = 0; i <= 3; i++) {
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+       }
+       printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+       printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+       printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+       printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+
+       /* added for IBM boot rom version 1.15 bios bar changes  -AK */
+
+       /* Disable region first */
+       out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+       /* PLB starting addr, PCI: 0x80000000 */
+       out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+       /* PCI start addr, 0x80000000 */
+       out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+       /* 512MB range of PLB to PCI */
+       out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+       /* Enable no pre-fetch, enable region */
+       out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+                                               (PPC405_PCI_UPPER_MEM -
+                                                PPC405_PCI_MEM_BASE)) | 0x01));
+
+       /* Disable region one */
+       out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+       out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+       out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+       out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+       out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+       out_le32((void *) &(pcip->ptm1ms), 0x00000001);
+
+       /* Disable region two */
+       out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+       out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+       out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+       out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+       out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+       out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+       out_le32((void *) &(pcip->ptm2la), 0x00000000);
+
+       /* Zero config bars */
+       for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+               early_write_config_dword(hose, hose->first_busno,
+                                        PCI_FUNC(hose->first_busno), bar,
+                                        0x00000000);
+               early_read_config_dword(hose, hose->first_busno,
+                                       PCI_FUNC(hose->first_busno), bar,
+                                       &bar_response);
+               DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+                   hose->first_busno, PCI_SLOT(hose->first_busno),
+                   PCI_FUNC(hose->first_busno), bar, bar_response);
+       }
+       /* end work arround */
+
+#ifdef DEBUG
+       printk("PCI bridge regs after fixup \n");
+       for (i = 0; i <= 3; i++) {
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+               printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+       }
+       printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+       printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+       printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+       printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif /* DEBUG */
+}
+
+void __init
+magicbox_setup_arch(void)
+{
+       ppc4xx_setup_arch();
+
+       ibm_ocp_set_emac(0, 1);
+
+       magicbox_early_serial_map();
+
+       /* Identify the system */
+       printk("MagicBox port (C) 2005 Karol Lewandowski <kl@jasmine.eu.org>\n");
+}
+
+void __init
+magicbox_map_io(void)
+{
+       ppc4xx_map_io();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       ppc4xx_init(r3, r4, r5, r6, r7);
+
+       ppc_md.setup_arch = magicbox_setup_arch;
+       ppc_md.setup_io_mappings = magicbox_map_io;
+
+#ifdef CONFIG_KGDB
+       ppc_md.early_serial_map = bubinga_early_serial_map;
+#endif
+
+}
diff --git a/target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.h b/target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.h
new file mode 100644 (file)
index 0000000..6ce1e5b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Support for IBM PPC 405EP-based MagicBox board
+ *
+ * Heavily based on bubinga.h
+ *
+ *
+ * Author: SAW (IBM), derived from walnut.h.
+ *         Maintained by MontaVista Software <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Softare Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifdef __KERNEL__
+#ifndef __MAGICBOX_H__
+#define __MAGICBOX_H__
+
+#include <linux/autoconf.h>
+#include <platforms/4xx/ibm405ep.h>
+#include <asm/ppcboot.h>
+
+/* Memory map for the "MagicBox" 405EP evaluation board -- generic 4xx. */
+
+/* The UART clock is based off an internal clock -
+ * define BASE_BAUD based on the internal clock and divider(s).
+ * Since BASE_BAUD must be a constant, we will initialize it
+ * using clock/divider values which OpenBIOS initializes
+ * for typical configurations at various CPU speeds.
+ * The base baud is calculated as (FWDA / EXT UART DIV / 16)
+ */
+#define BASE_BAUD       0
+
+/* Flash */
+#define PPC40x_FPGA_BASE       0xF0300000
+#define PPC40x_FPGA_REG_OFFS   1       /* offset to flash map reg */
+#define PPC40x_FLASH_ONBD_N(x) (x & 0x02)
+#define PPC40x_FLASH_SRAM_SEL(x) (x & 0x01)
+#define PPC40x_FLASH_LOW       0xFFF00000
+#define PPC40x_FLASH_HIGH      0xFFF80000
+#define PPC40x_FLASH_SIZE      0x80000
+
+#define PPC4xx_MACHINE_NAME    "MagicBox"
+
+#endif /* __MAGICBOX_H__ */
+#endif /* __KERNEL__ */
diff --git a/target/linux/magicbox-2.6/files/drivers/ide/ppc/magicbox_ide.c b/target/linux/magicbox-2.6/files/drivers/ide/ppc/magicbox_ide.c
new file mode 100644 (file)
index 0000000..d1f6d68
--- /dev/null
@@ -0,0 +1,147 @@
+/* Driver for MagicBox 2.0 onboard CompactFlash adapter.
+ * Written by Wojtek Kaniewski <wojtekka@toxygen.net>
+ *
+ * GNU General Public License.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+
+#define UIC0_PR 0xc4
+#define UIC0_TR 0xc5
+#define IRQ 25
+
+static int ide_offsets[IDE_NR_PORTS] = {0, 2, 4, 6, 8, 10, 12, 14, -1, -1};
+
+static u8 magicbox_ide_inb (unsigned long port)
+{
+       return (u8) (readw((void __iomem *) port) >> 8) & 255;
+}
+
+static u16 magicbox_ide_inw (unsigned long port)
+{
+       return (u16) readw((void __iomem *) port);
+}
+
+static void magicbox_ide_insw (unsigned long port, void *addr, u32 count)
+{
+       u16 *ptr;
+
+       for (ptr = addr; count--; ptr++)
+               *ptr = readw((void __iomem *) port);
+}
+
+static u32 magicbox_ide_inl (unsigned long port)
+{
+       return (u32) readl((void __iomem *) port);
+}
+
+static void magicbox_ide_insl (unsigned long port, void *addr, u32 count)
+{
+       u32 *ptr;
+
+       for (ptr = addr; count--; ptr++)
+               *ptr = readl((void __iomem *) port);
+}
+
+static void magicbox_ide_outb (u8 value, unsigned long port)
+{
+       writew(value << 8, (void __iomem *) port);
+}
+
+static void magicbox_ide_outbsync (ide_drive_t *drive, u8 value, unsigned long port)
+{
+       writew(value << 8, (void __iomem *) port);
+}
+
+static void magicbox_ide_outw (u16 value, unsigned long port)
+{
+       writew(value, (void __iomem *) port);
+}
+
+static void magicbox_ide_outsw (unsigned long port, void *addr, u32 count)
+{
+       u16 *ptr;
+
+       for (ptr = addr; count--; ptr++)
+               writew(*ptr, (void __iomem *) port);
+}
+
+static void magicbox_ide_outl (u32 value, unsigned long port)
+{
+       writel(value, (void __iomem *) port);
+}
+
+static void magicbox_ide_outsl (unsigned long port, void *addr, u32 count)
+{
+       u32 *ptr;
+
+       for (ptr = addr; count--; ptr++)
+               writel(*ptr, (void __iomem *) port);
+}
+
+
+static void __init ide_magicbox_register(unsigned long addr,
+                                        unsigned long caddr, int irq)
+{
+       hw_regs_t hw;
+       ide_hwif_t *hwif;
+
+       memset(&hw, 0, sizeof(hw));
+       ide_setup_ports(&hw, addr, ide_offsets, caddr + 12, 0, NULL,irq);
+
+       if (ide_register_hw(&hw, &hwif) != -1)
+       {
+               printk(KERN_NOTICE "magicbox-ide: Registered IDE-CF driver\n");
+               hwif->mmio = 2;
+               hwif->drives[0].unmask = 1;
+               hwif->OUTB = magicbox_ide_outb;
+               hwif->OUTBSYNC = magicbox_ide_outbsync;
+               hwif->OUTW = magicbox_ide_outw;
+               hwif->OUTSW = magicbox_ide_outsw;
+               hwif->OUTSL = magicbox_ide_outsl;
+               hwif->INB = magicbox_ide_inb;
+               hwif->INW = magicbox_ide_inw;
+               hwif->INSW = magicbox_ide_insw;
+               hwif->INSL = magicbox_ide_insl;
+       }
+}
+
+void __init ide_magicbox_init(void)
+{
+       volatile u16 *addr;
+       volatile u16 *caddr;
+
+       /* Turn on PerWE instead of PCIsomething */
+       mtdcr(DCRN_CPC0_PCI_BASE, mfdcr(DCRN_CPC0_PCI_BASE) | (0x80000000L >> 27));
+
+       /* PerCS1 (CF's CS0): base 0xff100000, 16-bit, rw */
+       mtdcr(DCRN_EBC_BASE, 1);
+       mtdcr(DCRN_EBC_BASE + 1, 0xff11a000);
+       mtdcr(DCRN_EBC_BASE, 0x11);
+       mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
+
+       /* PerCS2 (CF's CS1): base 0xff200000, 16-bit, rw */
+       mtdcr(DCRN_EBC_BASE, 2);
+       mtdcr(DCRN_EBC_BASE + 1, 0xff21a000);
+       mtdcr(DCRN_EBC_BASE, 0x12);
+       mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
+
+       /* Remap physical address space */
+       addr = ioremap_nocache(0xff100000, 4096);
+       caddr = ioremap_nocache(0xff200000, 4096);
+
+       /* Set interrupt to low-to-high-edge-triggered */
+       mtdcr(UIC0_TR, mfdcr(UIC0_TR) & ~(0x80000000L >> IRQ));
+       mtdcr(UIC0_PR, mfdcr(UIC0_PR) | (0x80000000L >> IRQ));
+
+       ide_magicbox_register((unsigned long)addr, (unsigned long)caddr, IRQ);
+}
+
diff --git a/target/linux/magicbox-2.6/files/drivers/mtd/maps/magicmap.c b/target/linux/magicbox-2.6/files/drivers/mtd/maps/magicmap.c
new file mode 100644 (file)
index 0000000..b654a3d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * magicmap.c: Copyleft 2005  Karol Lewandowski
+ *
+ * Mapping for MagicBox flash.
+ * Based on walnut.c.
+ *
+ * Heikki Lindholm <holindho@infradead.org>
+ *
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/autoconf.h>
+#include <asm/io.h>
+
+static struct mtd_info *flash;
+
+static struct map_info magic_map = {
+       .name =         "Magically mapped flash",
+       .phys =         0xffc00000,
+       .size =         0x400000,
+       .bankwidth =    2,
+};
+
+static struct mtd_partition magic_partitions[] = {
+       {
+               .name =   "linux",
+               .offset = 0x0,
+               .size =   0x3c0000,
+       },
+       {
+               .name =   "rootfs",
+               .offset = 0x100000,
+               .size =   0x2c0000,
+       },
+       {
+               .name =   "bootloader",
+               .offset = 0x3c0000,
+               .size =   0x040000,
+               .mask_flags = MTD_WRITEABLE,
+       },
+};
+
+int __init init_magic(void)
+{
+       u32 size, len;
+       
+       magic_map.virt =
+               (void __iomem *)ioremap(magic_map.phys, magic_map.size);
+
+       if (!magic_map.virt) {
+               printk("Failed to ioremap flash.\n");
+               return -EIO;
+       }
+
+       simple_map_init(&magic_map);
+
+       flash = do_map_probe("cfi_probe", &magic_map);
+       if (flash) {
+               flash->owner = THIS_MODULE;
+               if (flash->read(flash, 12, sizeof(u32), &len, (char *) &size) ||
+                       len != 4)
+                       return -ENXIO;
+               size += 0x40; /* header size of the uImage */
+               if (size < 0x400000) {
+                       /* skip to next erase block */
+                       if (size & (flash->erasesize - 1)) {
+                               size |= (flash->erasesize - 1);
+                               size += 1;
+                       }
+                       magic_partitions[1].offset = size;
+                       magic_partitions[1].size = magic_partitions[2].offset - size;
+               }
+               
+               add_mtd_partitions(flash, magic_partitions,
+                                       ARRAY_SIZE(magic_partitions));
+       } else {
+               printk("map probe failed for flash\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static void __exit cleanup_magic(void)
+{
+       if (flash) {
+               del_mtd_partitions(flash);
+               map_destroy(flash);
+       }
+
+       if (magic_map.virt) {
+               iounmap((void *)magic_map.virt);
+               magic_map.virt = NULL;
+       }
+}
+
+module_init(init_magic);
+module_exit(cleanup_magic);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Karol Lewandowski");
+MODULE_DESCRIPTION("MTD map and partitions for IBM 405EP MagicBox boards");
index 7c609e5d020b939e34e0299cc80ec5cd1fc7df74..873160d3bc666b4aaae974cf27404c8613c1c6c8 100644 (file)
@@ -18,8 +18,8 @@ diff -urN linux.old/arch/ppc/platforms/4xx/Kconfig linux.dev/arch/ppc/platforms/
  
  config IBM_OCP
        bool
--      depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
-+      depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT || MAGICBOX
+-      depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || TAISHAN || WALNUT
++      depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || TAISHAN || WALNUT || MAGICBOX
        default y
  
  config IBM_EMAC4
@@ -41,310 +41,6 @@ diff -urN linux.old/arch/ppc/platforms/4xx/Kconfig linux.dev/arch/ppc/platforms/
        default y
  
  config 405GP
-diff -urN linux.old/arch/ppc/platforms/4xx/magicbox.c linux.dev/arch/ppc/platforms/4xx/magicbox.c
---- linux.old/arch/ppc/platforms/4xx/magicbox.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/ppc/platforms/4xx/magicbox.c        2006-12-14 08:48:56.000000000 +0100
-@@ -0,0 +1,249 @@
-+/*
-+ * Support for IBM PPC 405EP-based MagicBox board 
-+ * Copyright (C) 2006  Karol Lewandowski
-+ *
-+ * Heavily based on bubinga.c
-+ *
-+ * Author: SAW (IBM), derived from walnut.c.
-+ *         Maintained by MontaVista Software <source@mvista.com>
-+ *
-+ * 2003 (c) MontaVista Softare Inc.  This file is licensed under the
-+ * terms of the GNU General Public License version 2. This program is
-+ * licensed "as is" without any warranty of any kind, whether express
-+ * or implied.
-+ */
-+
-+#include <linux/autoconf.h>
-+#include <linux/init.h>
-+#include <linux/smp.h>
-+#include <linux/threads.h>
-+#include <linux/param.h>
-+#include <linux/string.h>
-+#include <linux/blkdev.h>
-+#include <linux/pci.h>
-+#include <linux/tty.h>
-+#include <linux/serial.h>
-+#include <linux/serial_core.h>
-+
-+#include <asm/system.h>
-+#include <asm/pci-bridge.h>
-+#include <asm/processor.h>
-+#include <asm/machdep.h>
-+#include <asm/page.h>
-+#include <asm/time.h>
-+#include <asm/io.h>
-+#include <asm/kgdb.h>
-+#include <asm/ocp.h>
-+#include <asm/ibm_ocp_pci.h>
-+
-+#include <platforms/4xx/ibm405ep.h>
-+
-+#undef DEBUG
-+
-+#ifdef DEBUG
-+#define DBG(x...) printk(x)
-+#else
-+#define DBG(x...)
-+#endif
-+
-+extern bd_t __res;
-+
-+/* Some IRQs unique to board
-+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
-+ */
-+int __init
-+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-+{
-+      static char pci_irq_table[][4] =
-+          /*
-+           *      PCI IDSEL/INTPIN->INTLINE
-+           *      A       B       C       D
-+           */
-+      {
-+              {28, 28, 28, 28},       /* IDSEL 1 - PCI slot 1 */
-+              {29, 29, 29, 29},       /* IDSEL 2 - PCI slot 2 */
-+              {30, 30, 30, 30},       /* IDSEL 3 - PCI slot 3 */
-+              {31, 31, 31, 31},       /* IDSEL 4 - PCI slot 4 */
-+      };
-+
-+      const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
-+      return PCI_IRQ_TABLE_LOOKUP;
-+};
-+
-+
-+/* The serial clock for the chip is an internal clock determined by
-+ * different clock speeds/dividers.
-+ * Calculate the proper input baud rate and setup the serial driver.
-+ */
-+static void __init
-+magicbox_early_serial_map(void)
-+{
-+      u32 uart_div;
-+      int uart_clock;
-+      struct uart_port port;
-+
-+         /* Calculate the serial clock input frequency
-+          *
-+          * The base baud is the PLL OUTA (provided in the board info
-+          * structure) divided by the external UART Divisor, divided
-+          * by 16.
-+          */
-+      uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV);
-+      uart_clock = __res.bi_procfreq / uart_div;
-+
-+      /* Setup serial port access */
-+      memset(&port, 0, sizeof(port));
-+      port.membase = (void*)ACTING_UART0_IO_BASE;
-+      port.irq = ACTING_UART0_INT;
-+      port.uartclk = uart_clock;
-+      port.regshift = 0;
-+      port.iotype = SERIAL_IO_MEM;
-+      port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
-+      port.line = 0;
-+
-+      if (early_serial_setup(&port) != 0) {
-+              printk("Early serial init of port 0 failed\n");
-+      }
-+
-+      port.membase = (void*)ACTING_UART1_IO_BASE;
-+      port.irq = ACTING_UART1_INT;
-+      port.line = 1;
-+
-+      if (early_serial_setup(&port) != 0) {
-+              printk("Early serial init of port 1 failed\n");
-+      }
-+}
-+
-+void __init
-+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
-+{
-+      unsigned int bar_response, bar;
-+      /*
-+       * Expected PCI mapping:
-+       *
-+       *  PLB addr             PCI memory addr
-+       *  ---------------------       ---------------------
-+       *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
-+       *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
-+       *
-+       *  PLB addr             PCI io addr
-+       *  ---------------------       ---------------------
-+       *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
-+       *
-+       * The following code is simplified by assuming that the bootrom
-+       * has been well behaved in following this mapping.
-+       */
-+
-+#ifdef DEBUG
-+      int i;
-+
-+      printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
-+      printk("PCI bridge regs before fixup \n");
-+      for (i = 0; i <= 3; i++) {
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
-+      }
-+      printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-+      printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-+      printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-+      printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-+
-+#endif
-+
-+      /* added for IBM boot rom version 1.15 bios bar changes  -AK */
-+
-+      /* Disable region first */
-+      out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
-+      /* PLB starting addr, PCI: 0x80000000 */
-+      out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
-+      /* PCI start addr, 0x80000000 */
-+      out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
-+      /* 512MB range of PLB to PCI */
-+      out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
-+      /* Enable no pre-fetch, enable region */
-+      out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
-+                                              (PPC405_PCI_UPPER_MEM -
-+                                               PPC405_PCI_MEM_BASE)) | 0x01));
-+
-+      /* Disable region one */
-+      out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-+      out_le32((void *) &(pcip->ptm1ms), 0x00000001);
-+
-+      /* Disable region two */
-+      out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
-+      out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-+      out_le32((void *) &(pcip->ptm2ms), 0x00000000);
-+      out_le32((void *) &(pcip->ptm2la), 0x00000000);
-+
-+      /* Zero config bars */
-+      for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
-+              early_write_config_dword(hose, hose->first_busno,
-+                                       PCI_FUNC(hose->first_busno), bar,
-+                                       0x00000000);
-+              early_read_config_dword(hose, hose->first_busno,
-+                                      PCI_FUNC(hose->first_busno), bar,
-+                                      &bar_response);
-+              DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
-+                  hose->first_busno, PCI_SLOT(hose->first_busno),
-+                  PCI_FUNC(hose->first_busno), bar, bar_response);
-+      }
-+      /* end work arround */
-+
-+#ifdef DEBUG
-+      printk("PCI bridge regs after fixup \n");
-+      for (i = 0; i <= 3; i++) {
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
-+              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
-+      }
-+      printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-+      printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-+      printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-+      printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-+
-+#endif /* DEBUG */
-+}
-+
-+void __init
-+magicbox_setup_arch(void)
-+{
-+      ppc4xx_setup_arch();
-+
-+      ibm_ocp_set_emac(0, 1);
-+
-+      magicbox_early_serial_map();
-+
-+      /* Identify the system */
-+      printk("MagicBox port (C) 2005 Karol Lewandowski <kl@jasmine.eu.org>\n");
-+}
-+
-+void __init
-+magicbox_map_io(void)
-+{
-+      ppc4xx_map_io();
-+}
-+
-+void __init
-+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-+            unsigned long r6, unsigned long r7)
-+{
-+      ppc4xx_init(r3, r4, r5, r6, r7);
-+
-+      ppc_md.setup_arch = magicbox_setup_arch;
-+      ppc_md.setup_io_mappings = magicbox_map_io;
-+
-+#ifdef CONFIG_KGDB
-+      ppc_md.early_serial_map = bubinga_early_serial_map;
-+#endif
-+
-+}
-diff -urN linux.old/arch/ppc/platforms/4xx/magicbox.h linux.dev/arch/ppc/platforms/4xx/magicbox.h
---- linux.old/arch/ppc/platforms/4xx/magicbox.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/ppc/platforms/4xx/magicbox.h        2006-12-14 08:48:56.000000000 +0100
-@@ -0,0 +1,47 @@
-+/*
-+ * Support for IBM PPC 405EP-based MagicBox board
-+ *
-+ * Heavily based on bubinga.h
-+ *
-+ *
-+ * Author: SAW (IBM), derived from walnut.h.
-+ *         Maintained by MontaVista Software <source@mvista.com>
-+ *
-+ * 2003 (c) MontaVista Softare Inc.  This file is licensed under the
-+ * terms of the GNU General Public License version 2. This program is
-+ * licensed "as is" without any warranty of any kind, whether express
-+ * or implied.
-+ */
-+
-+#ifdef __KERNEL__
-+#ifndef __MAGICBOX_H__
-+#define __MAGICBOX_H__
-+
-+#include <linux/autoconf.h>
-+#include <platforms/4xx/ibm405ep.h>
-+#include <asm/ppcboot.h>
-+
-+/* Memory map for the "MagicBox" 405EP evaluation board -- generic 4xx. */
-+
-+/* The UART clock is based off an internal clock -
-+ * define BASE_BAUD based on the internal clock and divider(s).
-+ * Since BASE_BAUD must be a constant, we will initialize it
-+ * using clock/divider values which OpenBIOS initializes
-+ * for typical configurations at various CPU speeds.
-+ * The base baud is calculated as (FWDA / EXT UART DIV / 16)
-+ */
-+#define BASE_BAUD       0
-+
-+/* Flash */
-+#define PPC40x_FPGA_BASE      0xF0300000
-+#define PPC40x_FPGA_REG_OFFS  1       /* offset to flash map reg */
-+#define PPC40x_FLASH_ONBD_N(x)        (x & 0x02)
-+#define PPC40x_FLASH_SRAM_SEL(x) (x & 0x01)
-+#define PPC40x_FLASH_LOW      0xFFF00000
-+#define PPC40x_FLASH_HIGH     0xFFF80000
-+#define PPC40x_FLASH_SIZE     0x80000
-+
-+#define PPC4xx_MACHINE_NAME   "MagicBox"
-+
-+#endif /* __MAGICBOX_H__ */
-+#endif /* __KERNEL__ */
 diff -urN linux.old/arch/ppc/platforms/4xx/Makefile linux.dev/arch/ppc/platforms/4xx/Makefile
 --- linux.old/arch/ppc/platforms/4xx/Makefile  2006-11-29 22:57:37.000000000 +0100
 +++ linux.dev/arch/ppc/platforms/4xx/Makefile  2006-12-14 08:48:56.000000000 +0100
index 5d29a047d5487f8609fb0c8866395a630253d8eb..415daa51b595347d4aff203d82688f5b362581ed 100644 (file)
@@ -17,123 +17,6 @@ diff -urN linux.old/drivers/mtd/maps/Kconfig linux.dev/drivers/mtd/maps/Kconfig
  config MTD_EBONY
        tristate "Flash devices mapped on IBM 440GP Ebony"
        depends on MTD_JEDECPROBE && EBONY
-diff -urN linux.old/drivers/mtd/maps/magicmap.c linux.dev/drivers/mtd/maps/magicmap.c
---- linux.old/drivers/mtd/maps/magicmap.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/drivers/mtd/maps/magicmap.c      2006-08-30 06:52:34.000000000 +0200
-@@ -0,0 +1,113 @@
-+/*
-+ * magicmap.c: Copyleft 2005  Karol Lewandowski
-+ *
-+ * Mapping for MagicBox flash.
-+ * Based on walnut.c.
-+ *
-+ * Heikki Lindholm <holindho@infradead.org>
-+ *
-+ *
-+ * This program is free software; you can redistribute  it and/or modify it
-+ * under  the terms of  the GNU General  Public License as published by the
-+ * Free Software Foundation;  either version 2 of the  License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/autoconf.h>
-+#include <asm/io.h>
-+
-+static struct mtd_info *flash;
-+
-+static struct map_info magic_map = {
-+      .name =         "Magically mapped flash",
-+      .phys =         0xffc00000,
-+      .size =         0x400000,
-+      .bankwidth =    2,
-+};
-+
-+static struct mtd_partition magic_partitions[] = {
-+      {
-+              .name =   "linux",
-+              .offset = 0x0,
-+              .size =   0x3c0000,
-+      },
-+      {
-+              .name =   "rootfs",
-+              .offset = 0x100000,
-+              .size =   0x2c0000,
-+      },
-+      {
-+              .name =   "bootloader",
-+              .offset = 0x3c0000,
-+              .size =   0x040000,
-+              .mask_flags = MTD_WRITEABLE,
-+      },
-+};
-+
-+int __init init_magic(void)
-+{
-+      u32 size, len;
-+      
-+      magic_map.virt =
-+              (void __iomem *)ioremap(magic_map.phys, magic_map.size);
-+
-+      if (!magic_map.virt) {
-+              printk("Failed to ioremap flash.\n");
-+              return -EIO;
-+      }
-+
-+      simple_map_init(&magic_map);
-+
-+      flash = do_map_probe("cfi_probe", &magic_map);
-+      if (flash) {
-+              flash->owner = THIS_MODULE;
-+              if (flash->read(flash, 12, sizeof(u32), &len, (char *) &size) ||
-+                      len != 4)
-+                      return -ENXIO;
-+              size += 0x40; /* header size of the uImage */
-+              if (size < 0x400000) {
-+                      /* skip to next erase block */
-+                      if (size & (flash->erasesize - 1)) {
-+                              size |= (flash->erasesize - 1);
-+                              size += 1;
-+                      }
-+                      magic_partitions[1].offset = size;
-+                      magic_partitions[1].size = magic_partitions[2].offset - size;
-+              }
-+              
-+              add_mtd_partitions(flash, magic_partitions,
-+                                      ARRAY_SIZE(magic_partitions));
-+      } else {
-+              printk("map probe failed for flash\n");
-+              return -ENXIO;
-+      }
-+
-+      return 0;
-+}
-+
-+static void __exit cleanup_magic(void)
-+{
-+      if (flash) {
-+              del_mtd_partitions(flash);
-+              map_destroy(flash);
-+      }
-+
-+      if (magic_map.virt) {
-+              iounmap((void *)magic_map.virt);
-+              magic_map.virt = NULL;
-+      }
-+}
-+
-+module_init(init_magic);
-+module_exit(cleanup_magic);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Karol Lewandowski");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 405EP MagicBox boards");
 diff -urN linux.old/drivers/mtd/maps/Makefile linux.dev/drivers/mtd/maps/Makefile
 --- linux.old/drivers/mtd/maps/Makefile        2006-08-30 06:30:59.000000000 +0200
 +++ linux.dev/drivers/mtd/maps/Makefile        2006-08-30 06:11:51.000000000 +0200
index b5e12438f21453fc6ff1425d077ef4f447c7fa22..490cfca66532bd8778f56674a9a882a9ddd59fba 100644 (file)
@@ -2,10 +2,10 @@ diff -purN linux.old/drivers/ide/ide.c linux.dev/drivers/ide/ide.c
 --- linux.old/drivers/ide/ide.c        2007-01-10 20:10:37.000000000 +0100
 +++ linux.dev/drivers/ide/ide.c        2007-04-09 01:25:30.866800288 +0200
 @@ -1783,6 +1783,7 @@ done:
- extern void pnpide_init(void);
- extern void h8300_ide_init(void);
-+extern void ide_magicbox_init(void);
+ extern void __init pnpide_init(void);
+ extern void __exit pnpide_exit(void);
+ extern void __init h8300_ide_init(void);
++extern void __init ide_magicbox_init(void);
  
  /*
   * probe_for_hwifs() finds/initializes "known" IDE interfaces
@@ -19,2109 +19,6 @@ diff -purN linux.old/drivers/ide/ide.c linux.dev/drivers/ide/ide.c
  }
  
  void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-diff -purN linux.old/drivers/ide/ide.c.orig linux.dev/drivers/ide/ide.c.orig
---- linux.old/drivers/ide/ide.c.orig   1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/drivers/ide/ide.c.orig   2007-01-10 20:10:37.000000000 +0100
-@@ -0,0 +1,2099 @@
-+/*
-+ *  linux/drivers/ide/ide.c           Version 7.00beta2       Mar 05 2003
-+ *
-+ *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
-+ */
-+
-+/*
-+ *  Mostly written by Mark Lord  <mlord@pobox.com>
-+ *                and Gadi Oxman <gadio@netvision.net.il>
-+ *                and Andre Hedrick <andre@linux-ide.org>
-+ *
-+ *  See linux/MAINTAINERS for address of current maintainer.
-+ *
-+ * This is the multiple IDE interface driver, as evolved from hd.c.
-+ * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
-+ *   (usually 14 & 15).
-+ * There can be up to two drives per interface, as per the ATA-2 spec.
-+ *
-+ * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
-+ * Secondary:  ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
-+ * Tertiary:   ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
-+ * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
-+ * ...
-+ *
-+ *  From hd.c:
-+ *  |
-+ *  | It traverses the request-list, using interrupts to jump between functions.
-+ *  | As nearly all functions can be called within interrupts, we may not sleep.
-+ *  | Special care is recommended.  Have Fun!
-+ *  |
-+ *  | modified by Drew Eckhardt to check nr of hd's from the CMOS.
-+ *  |
-+ *  | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
-+ *  | in the early extended-partition checks and added DM partitions.
-+ *  |
-+ *  | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
-+ *  |
-+ *  | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
-+ *  | and general streamlining by Mark Lord (mlord@pobox.com).
-+ *
-+ *  October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
-+ *
-+ *    Mark Lord       (mlord@pobox.com)               (IDE Perf.Pkg)
-+ *    Delman Lee      (delman@ieee.org)               ("Mr. atdisk2")
-+ *    Scott Snyder    (snyder@fnald0.fnal.gov)        (ATAPI IDE cd-rom)
-+ *
-+ *  This was a rewrite of just about everything from hd.c, though some original
-+ *  code is still sprinkled about.  Think of it as a major evolution, with
-+ *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
-+ *
-+ *  Version 1.0 ALPHA initial code, primary i/f working okay
-+ *  Version 1.3 BETA  dual i/f on shared irq tested & working!
-+ *  Version 1.4 BETA  added auto probing for irq(s)
-+ *  Version 1.5 BETA  added ALPHA (untested) support for IDE cd-roms,
-+ *  ...
-+ * Version 5.50               allow values as small as 20 for idebus=
-+ * Version 5.51               force non io_32bit in drive_cmd_intr()
-+ *                    change delay_10ms() to delay_50ms() to fix problems
-+ * Version 5.52               fix incorrect invalidation of removable devices
-+ *                    add "hdx=slow" command line option
-+ * Version 5.60               start to modularize the driver; the disk and ATAPI
-+ *                     drivers can be compiled as loadable modules.
-+ *                    move IDE probe code to ide-probe.c
-+ *                    move IDE disk code to ide-disk.c
-+ *                    add support for generic IDE device subdrivers
-+ *                    add m68k code from Geert Uytterhoeven
-+ *                    probe all interfaces by default
-+ *                    add ioctl to (re)probe an interface
-+ * Version 6.00               use per device request queues
-+ *                    attempt to optimize shared hwgroup performance
-+ *                    add ioctl to manually adjust bandwidth algorithms
-+ *                    add kerneld support for the probe module
-+ *                    fix bug in ide_error()
-+ *                    fix bug in the first ide_get_lock() call for Atari
-+ *                    don't flush leftover data for ATAPI devices
-+ * Version 6.01               clear hwgroup->active while the hwgroup sleeps
-+ *                    support HDIO_GETGEO for floppies
-+ * Version 6.02               fix ide_ack_intr() call
-+ *                    check partition table on floppies
-+ * Version 6.03               handle bad status bit sequencing in ide_wait_stat()
-+ * Version 6.10               deleted old entries from this list of updates
-+ *                    replaced triton.c with ide-dma.c generic PCI DMA
-+ *                    added support for BIOS-enabled UltraDMA
-+ *                    rename all "promise" things to "pdc4030"
-+ *                    fix EZ-DRIVE handling on small disks
-+ * Version 6.11               fix probe error in ide_scan_devices()
-+ *                    fix ancient "jiffies" polling bugs
-+ *                    mask all hwgroup interrupts on each irq entry
-+ * Version 6.12               integrate ioctl and proc interfaces
-+ *                    fix parsing of "idex=" command line parameter
-+ * Version 6.13               add support for ide4/ide5 courtesy rjones@orchestream.com
-+ * Version 6.14               fixed IRQ sharing among PCI devices
-+ * Version 6.15               added SMP awareness to IDE drivers
-+ * Version 6.16               fixed various bugs; even more SMP friendly
-+ * Version 6.17               fix for newest EZ-Drive problem
-+ * Version 6.18               default unpartitioned-disk translation now "BIOS LBA"
-+ * Version 6.19               Re-design for a UNIFORM driver for all platforms,
-+ *                      model based on suggestions from Russell King and
-+ *                      Geert Uytterhoeven
-+ *                    Promise DC4030VL now supported.
-+ *                    add support for ide6/ide7
-+ *                    delay_50ms() changed to ide_delay_50ms() and exported.
-+ * Version 6.20               Added/Fixed Generic ATA-66 support and hwif detection.
-+ *                    Added hdx=flash to allow for second flash disk
-+ *                      detection w/o the hang loop.
-+ *                    Added support for ide8/ide9
-+ *                    Added idex=ata66 for the quirky chipsets that are
-+ *                      ATA-66 compliant, but have yet to determine a method
-+ *                      of verification of the 80c cable presence.
-+ *                      Specifically Promise's PDC20262 chipset.
-+ * Version 6.21               Fixing/Fixed SMP spinlock issue with insight from an old
-+ *                      hat that clarified original low level driver design.
-+ * Version 6.30               Added SMP support; fixed multmode issues.  -ml
-+ * Version 6.31               Debug Share INTR's and request queue streaming
-+ *                    Native ATA-100 support
-+ *                    Prep for Cascades Project
-+ * Version 7.00alpha  First named revision of ide rearrange
-+ *
-+ *  Some additional driver compile-time options are in ./include/linux/ide.h
-+ *
-+ *  To do, in likely order of completion:
-+ *    - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
-+ *
-+ */
-+
-+#define       REVISION        "Revision: 7.00alpha2"
-+#define       VERSION         "Id: ide.c 7.00a2 20020906"
-+
-+#undef REALLY_SLOW_IO         /* most systems can safely undef this */
-+
-+#define _IDE_C                        /* Tell ide.h it's really us */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/string.h>
-+#include <linux/kernel.h>
-+#include <linux/timer.h>
-+#include <linux/mm.h>
-+#include <linux/interrupt.h>
-+#include <linux/major.h>
-+#include <linux/errno.h>
-+#include <linux/genhd.h>
-+#include <linux/blkpg.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/pci.h>
-+#include <linux/delay.h>
-+#include <linux/ide.h>
-+#include <linux/completion.h>
-+#include <linux/reboot.h>
-+#include <linux/cdrom.h>
-+#include <linux/seq_file.h>
-+#include <linux/device.h>
-+#include <linux/bitops.h>
-+
-+#include <asm/byteorder.h>
-+#include <asm/irq.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+
-+
-+/* default maximum number of failures */
-+#define IDE_DEFAULT_MAX_FAILURES      1
-+
-+static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
-+                                      IDE2_MAJOR, IDE3_MAJOR,
-+                                      IDE4_MAJOR, IDE5_MAJOR,
-+                                      IDE6_MAJOR, IDE7_MAJOR,
-+                                      IDE8_MAJOR, IDE9_MAJOR };
-+
-+static int idebus_parameter;  /* holds the "idebus=" parameter */
-+static int system_bus_speed;  /* holds what we think is VESA/PCI bus speed */
-+static int initializing;      /* set while initializing built-in drivers */
-+
-+DECLARE_MUTEX(ide_cfg_sem);
-+ __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
-+
-+#ifdef CONFIG_BLK_DEV_IDEPCI
-+static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
-+#endif
-+
-+#ifdef CONFIG_IDEDMA_AUTO
-+int noautodma = 0;
-+#else
-+int noautodma = 1;
-+#endif
-+
-+EXPORT_SYMBOL(noautodma);
-+
-+/*
-+ * This is declared extern in ide.h, for access by other IDE modules:
-+ */
-+ide_hwif_t ide_hwifs[MAX_HWIFS];      /* master data repository */
-+
-+EXPORT_SYMBOL(ide_hwifs);
-+
-+/*
-+ * Do not even *think* about calling this!
-+ */
-+static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
-+{
-+      unsigned int unit;
-+
-+      /* bulk initialize hwif & drive info with zeros */
-+      memset(hwif, 0, sizeof(ide_hwif_t));
-+
-+      /* fill in any non-zero initial values */
-+      hwif->index     = index;
-+      hwif->major     = ide_hwif_to_major[index];
-+
-+      hwif->name[0]   = 'i';
-+      hwif->name[1]   = 'd';
-+      hwif->name[2]   = 'e';
-+      hwif->name[3]   = '0' + index;
-+
-+      hwif->bus_state = BUSSTATE_ON;
-+
-+      hwif->atapi_dma = 0;            /* disable all atapi dma */ 
-+      hwif->ultra_mask = 0x80;        /* disable all ultra */
-+      hwif->mwdma_mask = 0x80;        /* disable all mwdma */
-+      hwif->swdma_mask = 0x80;        /* disable all swdma */
-+
-+      init_completion(&hwif->gendev_rel_comp);
-+
-+      default_hwif_iops(hwif);
-+      default_hwif_transport(hwif);
-+      for (unit = 0; unit < MAX_DRIVES; ++unit) {
-+              ide_drive_t *drive = &hwif->drives[unit];
-+
-+              drive->media                    = ide_disk;
-+              drive->select.all               = (unit<<4)|0xa0;
-+              drive->hwif                     = hwif;
-+              drive->ctl                      = 0x08;
-+              drive->ready_stat               = READY_STAT;
-+              drive->bad_wstat                = BAD_W_STAT;
-+              drive->special.b.recalibrate    = 1;
-+              drive->special.b.set_geometry   = 1;
-+              drive->name[0]                  = 'h';
-+              drive->name[1]                  = 'd';
-+              drive->name[2]                  = 'a' + (index * MAX_DRIVES) + unit;
-+              drive->max_failures             = IDE_DEFAULT_MAX_FAILURES;
-+              drive->using_dma                = 0;
-+              drive->vdma                     = 0;
-+              INIT_LIST_HEAD(&drive->list);
-+              init_completion(&drive->gendev_rel_comp);
-+      }
-+}
-+
-+static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
-+{
-+      hw_regs_t hw;
-+
-+      memset(&hw, 0, sizeof(hw_regs_t));
-+
-+      ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq);
-+
-+      memcpy(&hwif->hw, &hw, sizeof(hw));
-+      memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports));
-+
-+      hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-+#ifdef CONFIG_BLK_DEV_HD
-+      if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
-+              hwif->noprobe = 1;      /* may be overridden by ide_setup() */
-+#endif
-+}
-+
-+extern void ide_arm_init(void);
-+
-+/*
-+ * init_ide_data() sets reasonable default values into all fields
-+ * of all instances of the hwifs and drives, but only on the first call.
-+ * Subsequent calls have no effect (they don't wipe out anything).
-+ *
-+ * This routine is normally called at driver initialization time,
-+ * but may also be called MUCH earlier during kernel "command-line"
-+ * parameter processing.  As such, we cannot depend on any other parts
-+ * of the kernel (such as memory allocation) to be functioning yet.
-+ *
-+ * This is too bad, as otherwise we could dynamically allocate the
-+ * ide_drive_t structs as needed, rather than always consuming memory
-+ * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
-+ *
-+ * FIXME: We should stuff the setup data into __init and copy the
-+ * relevant hwifs/allocate them properly during boot.
-+ */
-+#define MAGIC_COOKIE 0x12345678
-+static void __init init_ide_data (void)
-+{
-+      ide_hwif_t *hwif;
-+      unsigned int index;
-+      static unsigned long magic_cookie = MAGIC_COOKIE;
-+
-+      if (magic_cookie != MAGIC_COOKIE)
-+              return;         /* already initialized */
-+      magic_cookie = 0;
-+
-+      /* Initialise all interface structures */
-+      for (index = 0; index < MAX_HWIFS; ++index) {
-+              hwif = &ide_hwifs[index];
-+              init_hwif_data(hwif, index);
-+              init_hwif_default(hwif, index);
-+#if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
-+              hwif->irq = hwif->hw.irq =
-+                      ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
-+#endif
-+      }
-+#ifdef CONFIG_IDE_ARM
-+      initializing = 1;
-+      ide_arm_init();
-+      initializing = 0;
-+#endif
-+}
-+
-+/**
-+ *    ide_system_bus_speed    -       guess bus speed
-+ *
-+ *    ide_system_bus_speed() returns what we think is the system VESA/PCI
-+ *    bus speed (in MHz). This is used for calculating interface PIO timings.
-+ *    The default is 40 for known PCI systems, 50 otherwise.
-+ *    The "idebus=xx" parameter can be used to override this value.
-+ *    The actual value to be used is computed/displayed the first time
-+ *    through. Drivers should only use this as a last resort.
-+ *
-+ *    Returns a guessed speed in MHz.
-+ */
-+
-+static int ide_system_bus_speed(void)
-+{
-+#ifdef CONFIG_PCI
-+      static struct pci_device_id pci_default[] = {
-+              { PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) },
-+              { }
-+      };
-+#else
-+#define pci_default 0
-+#endif /* CONFIG_PCI */
-+
-+      if (!system_bus_speed) {
-+              if (idebus_parameter) {
-+                      /* user supplied value */
-+                      system_bus_speed = idebus_parameter;
-+              } else if (pci_dev_present(pci_default)) {
-+                      /* safe default value for PCI */
-+                      system_bus_speed = 33;
-+              } else {
-+                      /* safe default value for VESA and PCI */
-+                      system_bus_speed = 50;
-+              }
-+              printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
-+                      "for PIO modes%s\n", system_bus_speed,
-+                      idebus_parameter ? "" : "; override with idebus=xx");
-+      }
-+      return system_bus_speed;
-+}
-+
-+#ifdef CONFIG_PROC_FS
-+struct proc_dir_entry *proc_ide_root;
-+#endif
-+
-+static struct resource* hwif_request_region(ide_hwif_t *hwif,
-+                                          unsigned long addr, int num)
-+{
-+      struct resource *res = request_region(addr, num, hwif->name);
-+
-+      if (!res)
-+              printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-+                              hwif->name, addr, addr+num-1);
-+      return res;
-+}
-+
-+/**
-+ *    ide_hwif_request_regions - request resources for IDE
-+ *    @hwif: interface to use
-+ *
-+ *    Requests all the needed resources for an interface.
-+ *    Right now core IDE code does this work which is deeply wrong.
-+ *    MMIO leaves it to the controller driver,
-+ *    PIO will migrate this way over time.
-+ */
-+
-+int ide_hwif_request_regions(ide_hwif_t *hwif)
-+{
-+      unsigned long addr;
-+      unsigned int i;
-+
-+      if (hwif->mmio == 2)
-+              return 0;
-+      BUG_ON(hwif->mmio == 1);
-+      addr = hwif->io_ports[IDE_CONTROL_OFFSET];
-+      if (addr && !hwif_request_region(hwif, addr, 1))
-+              goto control_region_busy;
-+      hwif->straight8 = 0;
-+      addr = hwif->io_ports[IDE_DATA_OFFSET];
-+      if ((addr | 7) == hwif->io_ports[IDE_STATUS_OFFSET]) {
-+              if (!hwif_request_region(hwif, addr, 8))
-+                      goto data_region_busy;
-+              hwif->straight8 = 1;
-+              return 0;
-+      }
-+      for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-+              addr = hwif->io_ports[i];
-+              if (!hwif_request_region(hwif, addr, 1)) {
-+                      while (--i)
-+                              release_region(addr, 1);
-+                      goto data_region_busy;
-+              }
-+      }
-+      return 0;
-+
-+data_region_busy:
-+      addr = hwif->io_ports[IDE_CONTROL_OFFSET];
-+      if (addr)
-+              release_region(addr, 1);
-+control_region_busy:
-+      /* If any errors are return, we drop the hwif interface. */
-+      return -EBUSY;
-+}
-+
-+/**
-+ *    ide_hwif_release_regions - free IDE resources
-+ *
-+ *    Note that we only release the standard ports,
-+ *    and do not even try to handle any extra ports
-+ *    allocated for weird IDE interface chipsets.
-+ *
-+ *    Note also that we don't yet handle mmio resources here. More
-+ *    importantly our caller should be doing this so we need to 
-+ *    restructure this as a helper function for drivers.
-+ */
-+
-+void ide_hwif_release_regions(ide_hwif_t *hwif)
-+{
-+      u32 i = 0;
-+
-+      if (hwif->mmio == 2)
-+              return;
-+      if (hwif->io_ports[IDE_CONTROL_OFFSET])
-+              release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
-+      if (hwif->straight8) {
-+              release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
-+              return;
-+      }
-+      for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
-+              if (hwif->io_ports[i])
-+                      release_region(hwif->io_ports[i], 1);
-+}
-+
-+/**
-+ *    ide_hwif_restore        -       restore hwif to template
-+ *    @hwif: hwif to update
-+ *    @tmp_hwif: template
-+ *
-+ *    Restore hwif to a previous state by copying most settings
-+ *    from the template.
-+ */
-+
-+static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
-+{
-+      hwif->hwgroup                   = tmp_hwif->hwgroup;
-+
-+      hwif->gendev.parent             = tmp_hwif->gendev.parent;
-+
-+      hwif->proc                      = tmp_hwif->proc;
-+
-+      hwif->major                     = tmp_hwif->major;
-+      hwif->straight8                 = tmp_hwif->straight8;
-+      hwif->bus_state                 = tmp_hwif->bus_state;
-+
-+      hwif->atapi_dma                 = tmp_hwif->atapi_dma;
-+      hwif->ultra_mask                = tmp_hwif->ultra_mask;
-+      hwif->mwdma_mask                = tmp_hwif->mwdma_mask;
-+      hwif->swdma_mask                = tmp_hwif->swdma_mask;
-+
-+      hwif->chipset                   = tmp_hwif->chipset;
-+      hwif->hold                      = tmp_hwif->hold;
-+
-+#ifdef CONFIG_BLK_DEV_IDEPCI
-+      hwif->pci_dev                   = tmp_hwif->pci_dev;
-+      hwif->cds                       = tmp_hwif->cds;
-+#endif
-+
-+      hwif->tuneproc                  = tmp_hwif->tuneproc;
-+      hwif->speedproc                 = tmp_hwif->speedproc;
-+      hwif->selectproc                = tmp_hwif->selectproc;
-+      hwif->reset_poll                = tmp_hwif->reset_poll;
-+      hwif->pre_reset                 = tmp_hwif->pre_reset;
-+      hwif->resetproc                 = tmp_hwif->resetproc;
-+      hwif->intrproc                  = tmp_hwif->intrproc;
-+      hwif->maskproc                  = tmp_hwif->maskproc;
-+      hwif->quirkproc                 = tmp_hwif->quirkproc;
-+      hwif->busproc                   = tmp_hwif->busproc;
-+
-+      hwif->ata_input_data            = tmp_hwif->ata_input_data;
-+      hwif->ata_output_data           = tmp_hwif->ata_output_data;
-+      hwif->atapi_input_bytes         = tmp_hwif->atapi_input_bytes;
-+      hwif->atapi_output_bytes        = tmp_hwif->atapi_output_bytes;
-+
-+      hwif->dma_setup                 = tmp_hwif->dma_setup;
-+      hwif->dma_exec_cmd              = tmp_hwif->dma_exec_cmd;
-+      hwif->dma_start                 = tmp_hwif->dma_start;
-+      hwif->ide_dma_end               = tmp_hwif->ide_dma_end;
-+      hwif->ide_dma_check             = tmp_hwif->ide_dma_check;
-+      hwif->ide_dma_on                = tmp_hwif->ide_dma_on;
-+      hwif->ide_dma_off_quietly       = tmp_hwif->ide_dma_off_quietly;
-+      hwif->ide_dma_test_irq          = tmp_hwif->ide_dma_test_irq;
-+      hwif->ide_dma_host_on           = tmp_hwif->ide_dma_host_on;
-+      hwif->ide_dma_host_off          = tmp_hwif->ide_dma_host_off;
-+      hwif->ide_dma_lostirq           = tmp_hwif->ide_dma_lostirq;
-+      hwif->ide_dma_timeout           = tmp_hwif->ide_dma_timeout;
-+
-+      hwif->OUTB                      = tmp_hwif->OUTB;
-+      hwif->OUTBSYNC                  = tmp_hwif->OUTBSYNC;
-+      hwif->OUTW                      = tmp_hwif->OUTW;
-+      hwif->OUTL                      = tmp_hwif->OUTL;
-+      hwif->OUTSW                     = tmp_hwif->OUTSW;
-+      hwif->OUTSL                     = tmp_hwif->OUTSL;
-+
-+      hwif->INB                       = tmp_hwif->INB;
-+      hwif->INW                       = tmp_hwif->INW;
-+      hwif->INL                       = tmp_hwif->INL;
-+      hwif->INSW                      = tmp_hwif->INSW;
-+      hwif->INSL                      = tmp_hwif->INSL;
-+
-+      hwif->sg_max_nents              = tmp_hwif->sg_max_nents;
-+
-+      hwif->mmio                      = tmp_hwif->mmio;
-+      hwif->rqsize                    = tmp_hwif->rqsize;
-+      hwif->no_lba48                  = tmp_hwif->no_lba48;
-+
-+#ifndef CONFIG_BLK_DEV_IDECS
-+      hwif->irq                       = tmp_hwif->irq;
-+#endif
-+
-+      hwif->dma_base                  = tmp_hwif->dma_base;
-+      hwif->dma_master                = tmp_hwif->dma_master;
-+      hwif->dma_command               = tmp_hwif->dma_command;
-+      hwif->dma_vendor1               = tmp_hwif->dma_vendor1;
-+      hwif->dma_status                = tmp_hwif->dma_status;
-+      hwif->dma_vendor3               = tmp_hwif->dma_vendor3;
-+      hwif->dma_prdtable              = tmp_hwif->dma_prdtable;
-+
-+      hwif->config_data               = tmp_hwif->config_data;
-+      hwif->select_data               = tmp_hwif->select_data;
-+      hwif->extra_base                = tmp_hwif->extra_base;
-+      hwif->extra_ports               = tmp_hwif->extra_ports;
-+      hwif->autodma                   = tmp_hwif->autodma;
-+      hwif->udma_four                 = tmp_hwif->udma_four;
-+      hwif->no_dsc                    = tmp_hwif->no_dsc;
-+
-+      hwif->hwif_data                 = tmp_hwif->hwif_data;
-+}
-+
-+/**
-+ *    ide_unregister          -       free an IDE interface
-+ *    @index: index of interface (will change soon to a pointer)
-+ *
-+ *    Perform the final unregister of an IDE interface. At the moment
-+ *    we don't refcount interfaces so this will also get split up.
-+ *
-+ *    Locking:
-+ *    The caller must not hold the IDE locks
-+ *    The drive present/vanishing is not yet properly locked
-+ *    Take care with the callbacks. These have been split to avoid
-+ *    deadlocking the IDE layer. The shutdown callback is called
-+ *    before we take the lock and free resources. It is up to the
-+ *    caller to be sure there is no pending I/O here, and that
-+ *    the interface will not be reopened (present/vanishing locking
-+ *    isn't yet done BTW). After we commit to the final kill we
-+ *    call the cleanup callback with the ide locks held.
-+ *
-+ *    Unregister restores the hwif structures to the default state.
-+ *    This is raving bonkers.
-+ */
-+
-+void ide_unregister(unsigned int index)
-+{
-+      ide_drive_t *drive;
-+      ide_hwif_t *hwif, *g;
-+      static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
-+      ide_hwgroup_t *hwgroup;
-+      int irq_count = 0, unit;
-+
-+      BUG_ON(index >= MAX_HWIFS);
-+
-+      BUG_ON(in_interrupt());
-+      BUG_ON(irqs_disabled());
-+      down(&ide_cfg_sem);
-+      spin_lock_irq(&ide_lock);
-+      hwif = &ide_hwifs[index];
-+      if (!hwif->present)
-+              goto abort;
-+      for (unit = 0; unit < MAX_DRIVES; ++unit) {
-+              drive = &hwif->drives[unit];
-+              if (!drive->present)
-+                      continue;
-+              spin_unlock_irq(&ide_lock);
-+              device_unregister(&drive->gendev);
-+              wait_for_completion(&drive->gendev_rel_comp);
-+              spin_lock_irq(&ide_lock);
-+      }
-+      hwif->present = 0;
-+
-+      spin_unlock_irq(&ide_lock);
-+
-+      destroy_proc_ide_interface(hwif);
-+
-+      hwgroup = hwif->hwgroup;
-+      /*
-+       * free the irq if we were the only hwif using it
-+       */
-+      g = hwgroup->hwif;
-+      do {
-+              if (g->irq == hwif->irq)
-+                      ++irq_count;
-+              g = g->next;
-+      } while (g != hwgroup->hwif);
-+      if (irq_count == 1)
-+              free_irq(hwif->irq, hwgroup);
-+
-+      spin_lock_irq(&ide_lock);
-+      /*
-+       * Note that we only release the standard ports,
-+       * and do not even try to handle any extra ports
-+       * allocated for weird IDE interface chipsets.
-+       */
-+      ide_hwif_release_regions(hwif);
-+
-+      /*
-+       * Remove us from the hwgroup, and free
-+       * the hwgroup if we were the only member
-+       */
-+      if (hwif->next == hwif) {
-+              BUG_ON(hwgroup->hwif != hwif);
-+              kfree(hwgroup);
-+      } else {
-+              /* There is another interface in hwgroup.
-+               * Unlink us, and set hwgroup->drive and ->hwif to
-+               * something sane.
-+               */
-+              g = hwgroup->hwif;
-+              while (g->next != hwif)
-+                      g = g->next;
-+              g->next = hwif->next;
-+              if (hwgroup->hwif == hwif) {
-+                      /* Chose a random hwif for hwgroup->hwif.
-+                       * It's guaranteed that there are no drives
-+                       * left in the hwgroup.
-+                       */
-+                      BUG_ON(hwgroup->drive != NULL);
-+                      hwgroup->hwif = g;
-+              }
-+              BUG_ON(hwgroup->hwif == hwif);
-+      }
-+
-+      /* More messed up locking ... */
-+      spin_unlock_irq(&ide_lock);
-+      device_unregister(&hwif->gendev);
-+      wait_for_completion(&hwif->gendev_rel_comp);
-+
-+      /*
-+       * Remove us from the kernel's knowledge
-+       */
-+      blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
-+      kfree(hwif->sg_table);
-+      unregister_blkdev(hwif->major, hwif->name);
-+      spin_lock_irq(&ide_lock);
-+
-+      if (hwif->dma_base) {
-+              (void) ide_release_dma(hwif);
-+
-+              hwif->dma_base = 0;
-+              hwif->dma_master = 0;
-+              hwif->dma_command = 0;
-+              hwif->dma_vendor1 = 0;
-+              hwif->dma_status = 0;
-+              hwif->dma_vendor3 = 0;
-+              hwif->dma_prdtable = 0;
-+
-+              hwif->extra_base  = 0;
-+              hwif->extra_ports = 0;
-+      }
-+
-+      /* copy original settings */
-+      tmp_hwif = *hwif;
-+
-+      /* restore hwif data to pristine status */
-+      init_hwif_data(hwif, index);
-+      init_hwif_default(hwif, index);
-+
-+      ide_hwif_restore(hwif, &tmp_hwif);
-+
-+abort:
-+      spin_unlock_irq(&ide_lock);
-+      up(&ide_cfg_sem);
-+}
-+
-+EXPORT_SYMBOL(ide_unregister);
-+
-+
-+/**
-+ *    ide_setup_ports         -       set up IDE interface ports
-+ *    @hw: register descriptions
-+ *    @base: base register
-+ *    @offsets: table of register offsets
-+ *    @ctrl: control register
-+ *    @ack_irq: IRQ ack
-+ *    @irq: interrupt lie
-+ *
-+ *    Setup hw_regs_t structure described by parameters.  You
-+ *    may set up the hw structure yourself OR use this routine to
-+ *    do it for you. This is basically a helper
-+ *
-+ */
-+ 
-+void ide_setup_ports (        hw_regs_t *hw,
-+                      unsigned long base, int *offsets,
-+                      unsigned long ctrl, unsigned long intr,
-+                      ide_ack_intr_t *ack_intr,
-+/*
-+ *                    ide_io_ops_t *iops,
-+ */
-+                      int irq)
-+{
-+      int i;
-+
-+      memset(hw, 0, sizeof(hw_regs_t));
-+      for (i = 0; i < IDE_NR_PORTS; i++) {
-+              if (offsets[i] == -1) {
-+                      switch(i) {
-+                              case IDE_CONTROL_OFFSET:
-+                                      hw->io_ports[i] = ctrl;
-+                                      break;
-+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-+                              case IDE_IRQ_OFFSET:
-+                                      hw->io_ports[i] = intr;
-+                                      break;
-+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
-+                              default:
-+                                      hw->io_ports[i] = 0;
-+                                      break;
-+                      }
-+              } else {
-+                      hw->io_ports[i] = base + offsets[i];
-+              }
-+      }
-+      hw->irq = irq;
-+      hw->dma = NO_DMA;
-+      hw->ack_intr = ack_intr;
-+/*
-+ *    hw->iops = iops;
-+ */
-+}
-+
-+/**
-+ *    ide_register_hw_with_fixup      -       register IDE interface
-+ *    @hw: hardware registers
-+ *    @hwifp: pointer to returned hwif
-+ *    @fixup: fixup function
-+ *
-+ *    Register an IDE interface, specifying exactly the registers etc.
-+ *    Set init=1 iff calling before probes have taken place.
-+ *
-+ *    Returns -1 on error.
-+ */
-+
-+int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif))
-+{
-+      int index, retry = 1;
-+      ide_hwif_t *hwif;
-+
-+      do {
-+              for (index = 0; index < MAX_HWIFS; ++index) {
-+                      hwif = &ide_hwifs[index];
-+                      if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
-+                              goto found;
-+              }
-+              for (index = 0; index < MAX_HWIFS; ++index) {
-+                      hwif = &ide_hwifs[index];
-+                      if (hwif->hold)
-+                              continue;
-+                      if ((!hwif->present && !hwif->mate && !initializing) ||
-+                          (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
-+                              goto found;
-+              }
-+              for (index = 0; index < MAX_HWIFS; index++)
-+                      ide_unregister(index);
-+      } while (retry--);
-+      return -1;
-+found:
-+      if (hwif->present)
-+              ide_unregister(index);
-+      else if (!hwif->hold) {
-+              init_hwif_data(hwif, index);
-+              init_hwif_default(hwif, index);
-+      }
-+      if (hwif->present)
-+              return -1;
-+      memcpy(&hwif->hw, hw, sizeof(*hw));
-+      memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
-+      hwif->irq = hw->irq;
-+      hwif->noprobe = 0;
-+      hwif->chipset = hw->chipset;
-+      hwif->gendev.parent = hw->dev;
-+
-+      if (!initializing) {
-+              probe_hwif_init_with_fixup(hwif, fixup);
-+              create_proc_ide_interfaces();
-+      }
-+
-+      if (hwifp)
-+              *hwifp = hwif;
-+
-+      return (initializing || hwif->present) ? index : -1;
-+}
-+
-+EXPORT_SYMBOL(ide_register_hw_with_fixup);
-+
-+int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
-+{
-+      return ide_register_hw_with_fixup(hw, hwifp, NULL);
-+}
-+
-+EXPORT_SYMBOL(ide_register_hw);
-+
-+/*
-+ *    Locks for IDE setting functionality
-+ */
-+
-+DECLARE_MUTEX(ide_setting_sem);
-+
-+/**
-+ *    __ide_add_setting       -       add an ide setting option
-+ *    @drive: drive to use
-+ *    @name: setting name
-+ *    @rw: true if the function is read write
-+ *    @read_ioctl: function to call on read
-+ *    @write_ioctl: function to call on write
-+ *    @data_type: type of data
-+ *    @min: range minimum
-+ *    @max: range maximum
-+ *    @mul_factor: multiplication scale
-+ *    @div_factor: divison scale
-+ *    @data: private data field
-+ *    @set: setting
-+ *    @auto_remove: setting auto removal flag
-+ *
-+ *    Removes the setting named from the device if it is present.
-+ *    The function takes the settings_lock to protect against 
-+ *    parallel changes. This function must not be called from IRQ
-+ *    context. Returns 0 on success or -1 on failure.
-+ *
-+ *    BUGS: This code is seriously over-engineered. There is also
-+ *    magic about how the driver specific features are setup. If
-+ *    a driver is attached we assume the driver settings are auto
-+ *    remove.
-+ */
-+
-+static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
-+{
-+      ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
-+
-+      down(&ide_setting_sem);
-+      while ((*p) && strcmp((*p)->name, name) < 0)
-+              p = &((*p)->next);
-+      if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
-+              goto abort;
-+      if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
-+              goto abort;
-+      strcpy(setting->name, name);
-+      setting->rw = rw;
-+      setting->read_ioctl = read_ioctl;
-+      setting->write_ioctl = write_ioctl;
-+      setting->data_type = data_type;
-+      setting->min = min;
-+      setting->max = max;
-+      setting->mul_factor = mul_factor;
-+      setting->div_factor = div_factor;
-+      setting->data = data;
-+      setting->set = set;
-+      
-+      setting->next = *p;
-+      if (auto_remove)
-+              setting->auto_remove = 1;
-+      *p = setting;
-+      up(&ide_setting_sem);
-+      return 0;
-+abort:
-+      up(&ide_setting_sem);
-+      kfree(setting);
-+      return -1;
-+}
-+
-+int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
-+{
-+      return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
-+}
-+
-+EXPORT_SYMBOL(ide_add_setting);
-+
-+/**
-+ *    __ide_remove_setting    -       remove an ide setting option
-+ *    @drive: drive to use
-+ *    @name: setting name
-+ *
-+ *    Removes the setting named from the device if it is present.
-+ *    The caller must hold the setting semaphore.
-+ */
-+ 
-+static void __ide_remove_setting (ide_drive_t *drive, char *name)
-+{
-+      ide_settings_t **p, *setting;
-+
-+      p = (ide_settings_t **) &drive->settings;
-+
-+      while ((*p) && strcmp((*p)->name, name))
-+              p = &((*p)->next);
-+      if ((setting = (*p)) == NULL)
-+              return;
-+
-+      (*p) = setting->next;
-+      
-+      kfree(setting->name);
-+      kfree(setting);
-+}
-+
-+/**
-+ *    ide_find_setting_by_ioctl       -       find a drive specific ioctl
-+ *    @drive: drive to scan
-+ *    @cmd: ioctl command to handle
-+ *
-+ *    Scan's the device setting table for a matching entry and returns
-+ *    this or NULL if no entry is found. The caller must hold the
-+ *    setting semaphore
-+ */
-+ 
-+static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
-+{
-+      ide_settings_t *setting = drive->settings;
-+
-+      while (setting) {
-+              if (setting->read_ioctl == cmd || setting->write_ioctl == cmd)
-+                      break;
-+              setting = setting->next;
-+      }
-+      
-+      return setting;
-+}
-+
-+/**
-+ *    ide_find_setting_by_name        -       find a drive specific setting
-+ *    @drive: drive to scan
-+ *    @name: setting name
-+ *
-+ *    Scan's the device setting table for a matching entry and returns
-+ *    this or NULL if no entry is found. The caller must hold the
-+ *    setting semaphore
-+ */
-+ 
-+ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
-+{
-+      ide_settings_t *setting = drive->settings;
-+
-+      while (setting) {
-+              if (strcmp(setting->name, name) == 0)
-+                      break;
-+              setting = setting->next;
-+      }
-+      return setting;
-+}
-+
-+/**
-+ *    auto_remove_settings    -       remove driver specific settings
-+ *    @drive: drive
-+ *
-+ *    Automatically remove all the driver specific settings for this
-+ *    drive. This function may sleep and must not be called from IRQ
-+ *    context. The caller must hold ide_setting_sem.
-+ */
-+ 
-+static void auto_remove_settings (ide_drive_t *drive)
-+{
-+      ide_settings_t *setting;
-+repeat:
-+      setting = drive->settings;
-+      while (setting) {
-+              if (setting->auto_remove) {
-+                      __ide_remove_setting(drive, setting->name);
-+                      goto repeat;
-+              }
-+              setting = setting->next;
-+      }
-+}
-+
-+/**
-+ *    ide_read_setting        -       read an IDE setting
-+ *    @drive: drive to read from
-+ *    @setting: drive setting
-+ *
-+ *    Read a drive setting and return the value. The caller
-+ *    must hold the ide_setting_sem when making this call.
-+ *
-+ *    BUGS: the data return and error are the same return value
-+ *    so an error -EINVAL and true return of the same value cannot
-+ *    be told apart
-+ */
-+ 
-+int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
-+{
-+      int             val = -EINVAL;
-+      unsigned long   flags;
-+
-+      if ((setting->rw & SETTING_READ)) {
-+              spin_lock_irqsave(&ide_lock, flags);
-+              switch(setting->data_type) {
-+                      case TYPE_BYTE:
-+                              val = *((u8 *) setting->data);
-+                              break;
-+                      case TYPE_SHORT:
-+                              val = *((u16 *) setting->data);
-+                              break;
-+                      case TYPE_INT:
-+                      case TYPE_INTA:
-+                              val = *((u32 *) setting->data);
-+                              break;
-+              }
-+              spin_unlock_irqrestore(&ide_lock, flags);
-+      }
-+      return val;
-+}
-+
-+/**
-+ *    ide_spin_wait_hwgroup   -       wait for group
-+ *    @drive: drive in the group
-+ *
-+ *    Wait for an IDE device group to go non busy and then return
-+ *    holding the ide_lock which guards the hwgroup->busy status
-+ *    and right to use it.
-+ */
-+
-+int ide_spin_wait_hwgroup (ide_drive_t *drive)
-+{
-+      ide_hwgroup_t *hwgroup = HWGROUP(drive);
-+      unsigned long timeout = jiffies + (3 * HZ);
-+
-+      spin_lock_irq(&ide_lock);
-+
-+      while (hwgroup->busy) {
-+              unsigned long lflags;
-+              spin_unlock_irq(&ide_lock);
-+              local_irq_set(lflags);
-+              if (time_after(jiffies, timeout)) {
-+                      local_irq_restore(lflags);
-+                      printk(KERN_ERR "%s: channel busy\n", drive->name);
-+                      return -EBUSY;
-+              }
-+              local_irq_restore(lflags);
-+              spin_lock_irq(&ide_lock);
-+      }
-+      return 0;
-+}
-+
-+EXPORT_SYMBOL(ide_spin_wait_hwgroup);
-+
-+/**
-+ *    ide_write_setting       -       read an IDE setting
-+ *    @drive: drive to read from
-+ *    @setting: drive setting
-+ *    @val: value
-+ *
-+ *    Write a drive setting if it is possible. The caller
-+ *    must hold the ide_setting_sem when making this call.
-+ *
-+ *    BUGS: the data return and error are the same return value
-+ *    so an error -EINVAL and true return of the same value cannot
-+ *    be told apart
-+ *
-+ *    FIXME:  This should be changed to enqueue a special request
-+ *    to the driver to change settings, and then wait on a sema for completion.
-+ *    The current scheme of polling is kludgy, though safe enough.
-+ */
-+
-+int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
-+{
-+      int i;
-+      u32 *p;
-+
-+      if (!capable(CAP_SYS_ADMIN))
-+              return -EACCES;
-+      if (!(setting->rw & SETTING_WRITE))
-+              return -EPERM;
-+      if (val < setting->min || val > setting->max)
-+              return -EINVAL;
-+      if (setting->set)
-+              return setting->set(drive, val);
-+      if (ide_spin_wait_hwgroup(drive))
-+              return -EBUSY;
-+      switch (setting->data_type) {
-+              case TYPE_BYTE:
-+                      *((u8 *) setting->data) = val;
-+                      break;
-+              case TYPE_SHORT:
-+                      *((u16 *) setting->data) = val;
-+                      break;
-+              case TYPE_INT:
-+                      *((u32 *) setting->data) = val;
-+                      break;
-+              case TYPE_INTA:
-+                      p = (u32 *) setting->data;
-+                      for (i = 0; i < 1 << PARTN_BITS; i++, p++)
-+                              *p = val;
-+                      break;
-+      }
-+      spin_unlock_irq(&ide_lock);
-+      return 0;
-+}
-+
-+static int set_io_32bit(ide_drive_t *drive, int arg)
-+{
-+      drive->io_32bit = arg;
-+#ifdef CONFIG_BLK_DEV_DTC2278
-+      if (HWIF(drive)->chipset == ide_dtc2278)
-+              HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
-+#endif /* CONFIG_BLK_DEV_DTC2278 */
-+      return 0;
-+}
-+
-+static int set_using_dma (ide_drive_t *drive, int arg)
-+{
-+#ifdef CONFIG_BLK_DEV_IDEDMA
-+      if (!drive->id || !(drive->id->capability & 1))
-+              return -EPERM;
-+      if (HWIF(drive)->ide_dma_check == NULL)
-+              return -EPERM;
-+      if (arg) {
-+              if (HWIF(drive)->ide_dma_check(drive)) return -EIO;
-+              if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
-+      } else {
-+              if (__ide_dma_off(drive))
-+                      return -EIO;
-+      }
-+      return 0;
-+#else
-+      return -EPERM;
-+#endif
-+}
-+
-+static int set_pio_mode (ide_drive_t *drive, int arg)
-+{
-+      struct request rq;
-+
-+      if (!HWIF(drive)->tuneproc)
-+              return -ENOSYS;
-+      if (drive->special.b.set_tune)
-+              return -EBUSY;
-+      ide_init_drive_cmd(&rq);
-+      drive->tune_req = (u8) arg;
-+      drive->special.b.set_tune = 1;
-+      (void) ide_do_drive_cmd(drive, &rq, ide_wait);
-+      return 0;
-+}
-+
-+static int set_xfer_rate (ide_drive_t *drive, int arg)
-+{
-+      int err = ide_wait_cmd(drive,
-+                      WIN_SETFEATURES, (u8) arg,
-+                      SETFEATURES_XFER, 0, NULL);
-+
-+      if (!err && arg) {
-+              ide_set_xfer_rate(drive, (u8) arg);
-+              ide_driveid_update(drive);
-+      }
-+      return err;
-+}
-+
-+/**
-+ *    ide_add_generic_settings        -       generic ide settings
-+ *    @drive: drive being configured
-+ *
-+ *    Add the generic parts of the system settings to the /proc files and
-+ *    ioctls for this IDE device. The caller must not be holding the
-+ *    ide_setting_sem.
-+ */
-+
-+void ide_add_generic_settings (ide_drive_t *drive)
-+{
-+/*
-+ *                      drive         setting name            read/write access                               read ioctl              write ioctl             data type       min     max                             mul_factor      div_factor      data pointer                    set function
-+ */
-+      __ide_add_setting(drive,        "io_32bit",             drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT,         HDIO_SET_32BIT,         TYPE_BYTE,      0,      1 + (SUPPORT_VLB_SYNC << 1),    1,              1,              &drive->io_32bit,               set_io_32bit,   0);
-+      __ide_add_setting(drive,        "keepsettings",         SETTING_RW,                                     HDIO_GET_KEEPSETTINGS,  HDIO_SET_KEEPSETTINGS,  TYPE_BYTE,      0,      1,                              1,              1,              &drive->keep_settings,          NULL,           0);
-+      __ide_add_setting(drive,        "nice1",                SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->nice1,                  NULL,           0);
-+      __ide_add_setting(drive,        "pio_mode",             SETTING_WRITE,                                  -1,                     HDIO_SET_PIO_MODE,      TYPE_BYTE,      0,      255,                            1,              1,              NULL,                           set_pio_mode,   0);
-+      __ide_add_setting(drive,        "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   HDIO_GET_UNMASKINTR,    HDIO_SET_UNMASKINTR,    TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL,           0);
-+      __ide_add_setting(drive,        "using_dma",            SETTING_RW,                                     HDIO_GET_DMA,           HDIO_SET_DMA,           TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma,  0);
-+      __ide_add_setting(drive,        "init_speed",           SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->init_speed,             NULL,           0);
-+      __ide_add_setting(drive,        "current_speed",        SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->current_speed,          set_xfer_rate,  0);
-+      __ide_add_setting(drive,        "number",               SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL,           0);
-+}
-+
-+/**
-+ *    system_bus_clock        -       clock guess
-+ *
-+ *    External version of the bus clock guess used by very old IDE drivers
-+ *    for things like VLB timings. Should not be used.
-+ */
-+
-+int system_bus_clock (void)
-+{
-+      return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
-+}
-+
-+EXPORT_SYMBOL(system_bus_clock);
-+
-+static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
-+{
-+      ide_drive_t *drive = dev->driver_data;
-+      struct request rq;
-+      struct request_pm_state rqpm;
-+      ide_task_t args;
-+
-+      memset(&rq, 0, sizeof(rq));
-+      memset(&rqpm, 0, sizeof(rqpm));
-+      memset(&args, 0, sizeof(args));
-+      rq.cmd_type = REQ_TYPE_PM_SUSPEND;
-+      rq.special = &args;
-+      rq.data = &rqpm;
-+      rqpm.pm_step = ide_pm_state_start_suspend;
-+      if (mesg.event == PM_EVENT_PRETHAW)
-+              mesg.event = PM_EVENT_FREEZE;
-+      rqpm.pm_state = mesg.event;
-+
-+      return ide_do_drive_cmd(drive, &rq, ide_wait);
-+}
-+
-+static int generic_ide_resume(struct device *dev)
-+{
-+      ide_drive_t *drive = dev->driver_data;
-+      struct request rq;
-+      struct request_pm_state rqpm;
-+      ide_task_t args;
-+
-+      memset(&rq, 0, sizeof(rq));
-+      memset(&rqpm, 0, sizeof(rqpm));
-+      memset(&args, 0, sizeof(args));
-+      rq.cmd_type = REQ_TYPE_PM_RESUME;
-+      rq.special = &args;
-+      rq.data = &rqpm;
-+      rqpm.pm_step = ide_pm_state_start_resume;
-+      rqpm.pm_state = PM_EVENT_ON;
-+
-+      return ide_do_drive_cmd(drive, &rq, ide_head_wait);
-+}
-+
-+int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
-+                      unsigned int cmd, unsigned long arg)
-+{
-+      ide_settings_t *setting;
-+      ide_driver_t *drv;
-+      int err = 0;
-+      void __user *p = (void __user *)arg;
-+
-+      down(&ide_setting_sem);
-+      if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
-+              if (cmd == setting->read_ioctl) {
-+                      err = ide_read_setting(drive, setting);
-+                      up(&ide_setting_sem);
-+                      return err >= 0 ? put_user(err, (long __user *)arg) : err;
-+              } else {
-+                      if (bdev != bdev->bd_contains)
-+                              err = -EINVAL;
-+                      else
-+                              err = ide_write_setting(drive, setting, arg);
-+                      up(&ide_setting_sem);
-+                      return err;
-+              }
-+      }
-+      up(&ide_setting_sem);
-+
-+      switch (cmd) {
-+              case HDIO_OBSOLETE_IDENTITY:
-+              case HDIO_GET_IDENTITY:
-+                      if (bdev != bdev->bd_contains)
-+                              return -EINVAL;
-+                      if (drive->id_read == 0)
-+                              return -ENOMSG;
-+                      if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
-+                              return -EFAULT;
-+                      return 0;
-+
-+              case HDIO_GET_NICE:
-+                      return put_user(drive->dsc_overlap      <<      IDE_NICE_DSC_OVERLAP    |
-+                                      drive->atapi_overlap    <<      IDE_NICE_ATAPI_OVERLAP  |
-+                                      drive->nice0            <<      IDE_NICE_0              |
-+                                      drive->nice1            <<      IDE_NICE_1              |
-+                                      drive->nice2            <<      IDE_NICE_2,
-+                                      (long __user *) arg);
-+
-+#ifdef CONFIG_IDE_TASK_IOCTL
-+              case HDIO_DRIVE_TASKFILE:
-+                      if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-+                              return -EACCES;
-+                      switch(drive->media) {
-+                              case ide_disk:
-+                                      return ide_taskfile_ioctl(drive, cmd, arg);
-+                              default:
-+                                      return -ENOMSG;
-+                      }
-+#endif /* CONFIG_IDE_TASK_IOCTL */
-+
-+              case HDIO_DRIVE_CMD:
-+                      if (!capable(CAP_SYS_RAWIO))
-+                              return -EACCES;
-+                      return ide_cmd_ioctl(drive, cmd, arg);
-+
-+              case HDIO_DRIVE_TASK:
-+                      if (!capable(CAP_SYS_RAWIO))
-+                              return -EACCES;
-+                      return ide_task_ioctl(drive, cmd, arg);
-+
-+              case HDIO_SCAN_HWIF:
-+              {
-+                      hw_regs_t hw;
-+                      int args[3];
-+                      if (!capable(CAP_SYS_RAWIO)) return -EACCES;
-+                      if (copy_from_user(args, p, 3 * sizeof(int)))
-+                              return -EFAULT;
-+                      memset(&hw, 0, sizeof(hw));
-+                      ide_init_hwif_ports(&hw, (unsigned long) args[0],
-+                                          (unsigned long) args[1], NULL);
-+                      hw.irq = args[2];
-+                      if (ide_register_hw(&hw, NULL) == -1)
-+                              return -EIO;
-+                      return 0;
-+              }
-+              case HDIO_UNREGISTER_HWIF:
-+                      if (!capable(CAP_SYS_RAWIO)) return -EACCES;
-+                      /* (arg > MAX_HWIFS) checked in function */
-+                      ide_unregister(arg);
-+                      return 0;
-+              case HDIO_SET_NICE:
-+                      if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-+                      if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
-+                              return -EPERM;
-+                      drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
-+                      drv = *(ide_driver_t **)bdev->bd_disk->private_data;
-+                      if (drive->dsc_overlap && !drv->supports_dsc_overlap) {
-+                              drive->dsc_overlap = 0;
-+                              return -EPERM;
-+                      }
-+                      drive->nice1 = (arg >> IDE_NICE_1) & 1;
-+                      return 0;
-+              case HDIO_DRIVE_RESET:
-+              {
-+                      unsigned long flags;
-+                      if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-+                      
-+                      /*
-+                       *      Abort the current command on the
-+                       *      group if there is one, taking
-+                       *      care not to allow anything else
-+                       *      to be queued and to die on the
-+                       *      spot if we miss one somehow
-+                       */
-+
-+                      spin_lock_irqsave(&ide_lock, flags);
-+
-+                      if (HWGROUP(drive)->resetting) {
-+                              spin_unlock_irqrestore(&ide_lock, flags);
-+                              return -EBUSY;
-+                      }
-+
-+                      ide_abort(drive, "drive reset");
-+
-+                      BUG_ON(HWGROUP(drive)->handler);
-+                              
-+                      /* Ensure nothing gets queued after we
-+                         drop the lock. Reset will clear the busy */
-+                 
-+                      HWGROUP(drive)->busy = 1;
-+                      spin_unlock_irqrestore(&ide_lock, flags);
-+                      (void) ide_do_reset(drive);
-+
-+                      return 0;
-+              }
-+
-+              case CDROMEJECT:
-+              case CDROMCLOSETRAY:
-+                      return scsi_cmd_ioctl(file, bdev->bd_disk, cmd, p);
-+
-+              case HDIO_GET_BUSSTATE:
-+                      if (!capable(CAP_SYS_ADMIN))
-+                              return -EACCES;
-+                      if (put_user(HWIF(drive)->bus_state, (long __user *)arg))
-+                              return -EFAULT;
-+                      return 0;
-+
-+              case HDIO_SET_BUSSTATE:
-+                      if (!capable(CAP_SYS_ADMIN))
-+                              return -EACCES;
-+                      if (HWIF(drive)->busproc)
-+                              return HWIF(drive)->busproc(drive, (int)arg);
-+                      return -EOPNOTSUPP;
-+              default:
-+                      return -EINVAL;
-+      }
-+}
-+
-+EXPORT_SYMBOL(generic_ide_ioctl);
-+
-+/*
-+ * stridx() returns the offset of c within s,
-+ * or -1 if c is '\0' or not found within s.
-+ */
-+static int __init stridx (const char *s, char c)
-+{
-+      char *i = strchr(s, c);
-+      return (i && c) ? i - s : -1;
-+}
-+
-+/*
-+ * match_parm() does parsing for ide_setup():
-+ *
-+ * 1. the first char of s must be '='.
-+ * 2. if the remainder matches one of the supplied keywords,
-+ *     the index (1 based) of the keyword is negated and returned.
-+ * 3. if the remainder is a series of no more than max_vals numbers
-+ *     separated by commas, the numbers are saved in vals[] and a
-+ *     count of how many were saved is returned.  Base10 is assumed,
-+ *     and base16 is allowed when prefixed with "0x".
-+ * 4. otherwise, zero is returned.
-+ */
-+static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
-+{
-+      static const char *decimal = "0123456789";
-+      static const char *hex = "0123456789abcdef";
-+      int i, n;
-+
-+      if (*s++ == '=') {
-+              /*
-+               * Try matching against the supplied keywords,
-+               * and return -(index+1) if we match one
-+               */
-+              if (keywords != NULL) {
-+                      for (i = 0; *keywords != NULL; ++i) {
-+                              if (!strcmp(s, *keywords++))
-+                                      return -(i+1);
-+                      }
-+              }
-+              /*
-+               * Look for a series of no more than "max_vals"
-+               * numeric values separated by commas, in base10,
-+               * or base16 when prefixed with "0x".
-+               * Return a count of how many were found.
-+               */
-+              for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
-+                      vals[n] = i;
-+                      while ((i = stridx(decimal, *++s)) >= 0)
-+                              vals[n] = (vals[n] * 10) + i;
-+                      if (*s == 'x' && !vals[n]) {
-+                              while ((i = stridx(hex, *++s)) >= 0)
-+                                      vals[n] = (vals[n] * 0x10) + i;
-+                      }
-+                      if (++n == max_vals)
-+                              break;
-+                      if (*s == ',' || *s == ';')
-+                              ++s;
-+              }
-+              if (!*s)
-+                      return n;
-+      }
-+      return 0;       /* zero = nothing matched */
-+}
-+
-+#ifdef CONFIG_BLK_DEV_ALI14XX
-+static int __initdata probe_ali14xx;
-+extern int ali14xx_init(void);
-+#endif
-+#ifdef CONFIG_BLK_DEV_UMC8672
-+static int __initdata probe_umc8672;
-+extern int umc8672_init(void);
-+#endif
-+#ifdef CONFIG_BLK_DEV_DTC2278
-+static int __initdata probe_dtc2278;
-+extern int dtc2278_init(void);
-+#endif
-+#ifdef CONFIG_BLK_DEV_HT6560B
-+static int __initdata probe_ht6560b;
-+extern int ht6560b_init(void);
-+#endif
-+#ifdef CONFIG_BLK_DEV_QD65XX
-+static int __initdata probe_qd65xx;
-+extern int qd65xx_init(void);
-+#endif
-+
-+static int __initdata is_chipset_set[MAX_HWIFS];
-+
-+/*
-+ * ide_setup() gets called VERY EARLY during initialization,
-+ * to handle kernel "command line" strings beginning with "hdx=" or "ide".
-+ *
-+ * Remember to update Documentation/ide.txt if you change something here.
-+ */
-+static int __init ide_setup(char *s)
-+{
-+      int i, vals[3];
-+      ide_hwif_t *hwif;
-+      ide_drive_t *drive;
-+      unsigned int hw, unit;
-+      const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
-+      const char max_hwif  = '0' + (MAX_HWIFS - 1);
-+
-+      
-+      if (strncmp(s,"hd",2) == 0 && s[2] == '=')      /* hd= is for hd.c   */
-+              return 0;                               /* driver and not us */
-+
-+      if (strncmp(s,"ide",3) && strncmp(s,"idebus",6) && strncmp(s,"hd",2))
-+              return 0;
-+
-+      printk(KERN_INFO "ide_setup: %s", s);
-+      init_ide_data ();
-+
-+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-+      if (!strcmp(s, "ide=doubler")) {
-+              extern int ide_doubler;
-+
-+              printk(" : Enabled support for IDE doublers\n");
-+              ide_doubler = 1;
-+              return 1;
-+      }
-+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-+
-+      if (!strcmp(s, "ide=nodma")) {
-+              printk(" : Prevented DMA\n");
-+              noautodma = 1;
-+              return 1;
-+      }
-+
-+#ifdef CONFIG_BLK_DEV_IDEPCI
-+      if (!strcmp(s, "ide=reverse")) {
-+              ide_scan_direction = 1;
-+              printk(" : Enabled support for IDE inverse scan order.\n");
-+              return 1;
-+      }
-+#endif /* CONFIG_BLK_DEV_IDEPCI */
-+
-+      /*
-+       * Look for drive options:  "hdx="
-+       */
-+      if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
-+              const char *hd_words[] = {
-+                      "none", "noprobe", "nowerr", "cdrom", "serialize",
-+                      "autotune", "noautotune", "minus8", "swapdata", "bswap",
-+                      "noflush", "remap", "remap63", "scsi", NULL };
-+              unit = s[2] - 'a';
-+              hw   = unit / MAX_DRIVES;
-+              unit = unit % MAX_DRIVES;
-+              hwif = &ide_hwifs[hw];
-+              drive = &hwif->drives[unit];
-+              if (strncmp(s + 4, "ide-", 4) == 0) {
-+                      strlcpy(drive->driver_req, s + 4, sizeof(drive->driver_req));
-+                      goto done;
-+              }
-+              switch (match_parm(&s[3], hd_words, vals, 3)) {
-+                      case -1: /* "none" */
-+                      case -2: /* "noprobe" */
-+                              drive->noprobe = 1;
-+                              goto done;
-+                      case -3: /* "nowerr" */
-+                              drive->bad_wstat = BAD_R_STAT;
-+                              hwif->noprobe = 0;
-+                              goto done;
-+                      case -4: /* "cdrom" */
-+                              drive->present = 1;
-+                              drive->media = ide_cdrom;
-+                              /* an ATAPI device ignores DRDY */
-+                              drive->ready_stat = 0;
-+                              hwif->noprobe = 0;
-+                              goto done;
-+                      case -5: /* "serialize" */
-+                              printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
-+                              goto do_serialize;
-+                      case -6: /* "autotune" */
-+                              drive->autotune = IDE_TUNE_AUTO;
-+                              goto obsolete_option;
-+                      case -7: /* "noautotune" */
-+                              drive->autotune = IDE_TUNE_NOAUTO;
-+                              goto obsolete_option;
-+                      case -9: /* "swapdata" */
-+                      case -10: /* "bswap" */
-+                              drive->bswap = 1;
-+                              goto done;
-+                      case -11: /* noflush */
-+                              drive->noflush = 1;
-+                              goto done;
-+                      case -12: /* "remap" */
-+                              drive->remap_0_to_1 = 1;
-+                              goto done;
-+                      case -13: /* "remap63" */
-+                              drive->sect0 = 63;
-+                              goto done;
-+                      case -14: /* "scsi" */
-+                              drive->scsi = 1;
-+                              goto done;
-+                      case 3: /* cyl,head,sect */
-+                              drive->media    = ide_disk;
-+                              drive->ready_stat = READY_STAT;
-+                              drive->cyl      = drive->bios_cyl  = vals[0];
-+                              drive->head     = drive->bios_head = vals[1];
-+                              drive->sect     = drive->bios_sect = vals[2];
-+                              drive->present  = 1;
-+                              drive->forced_geom = 1;
-+                              hwif->noprobe = 0;
-+                              goto done;
-+                      default:
-+                              goto bad_option;
-+              }
-+      }
-+
-+      if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
-+              goto bad_option;
-+      /*
-+       * Look for bus speed option:  "idebus="
-+       */
-+      if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
-+              if (match_parm(&s[6], NULL, vals, 1) != 1)
-+                      goto bad_option;
-+              if (vals[0] >= 20 && vals[0] <= 66) {
-+                      idebus_parameter = vals[0];
-+              } else
-+                      printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
-+              goto done;
-+      }
-+      /*
-+       * Look for interface options:  "idex="
-+       */
-+      if (s[3] >= '0' && s[3] <= max_hwif) {
-+              /*
-+               * Be VERY CAREFUL changing this: note hardcoded indexes below
-+               * (-8, -9, -10) are reserved to ease the hardcoding.
-+               */
-+              static const char *ide_words[] = {
-+                      "noprobe", "serialize", "autotune", "noautotune", 
-+                      "reset", "dma", "ata66", "minus8", "minus9",
-+                      "minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
-+                      "dtc2278", "umc8672", "ali14xx", NULL };
-+              hw = s[3] - '0';
-+              hwif = &ide_hwifs[hw];
-+              i = match_parm(&s[4], ide_words, vals, 3);
-+
-+              /*
-+               * Cryptic check to ensure chipset not already set for hwif.
-+               * Note: we can't depend on hwif->chipset here.
-+               */
-+              if ((i >= -18 && i <= -11) || (i > 0 && i <= 3)) {
-+                      /* chipset already specified */
-+                      if (is_chipset_set[hw])
-+                              goto bad_option;
-+                      if (i > -18 && i <= -11) {
-+                              /* these drivers are for "ide0=" only */
-+                              if (hw != 0)
-+                                      goto bad_hwif;
-+                              /* chipset already specified for 2nd port */
-+                              if (is_chipset_set[hw+1])
-+                                      goto bad_option;
-+                      }
-+                      is_chipset_set[hw] = 1;
-+                      printk("\n");
-+              }
-+
-+              switch (i) {
-+#ifdef CONFIG_BLK_DEV_ALI14XX
-+                      case -17: /* "ali14xx" */
-+                              probe_ali14xx = 1;
-+                              goto done;
-+#endif
-+#ifdef CONFIG_BLK_DEV_UMC8672
-+                      case -16: /* "umc8672" */
-+                              probe_umc8672 = 1;
-+                              goto done;
-+#endif
-+#ifdef CONFIG_BLK_DEV_DTC2278
-+                      case -15: /* "dtc2278" */
-+                              probe_dtc2278 = 1;
-+                              goto done;
-+#endif
-+#ifdef CONFIG_BLK_DEV_CMD640
-+                      case -14: /* "cmd640_vlb" */
-+                      {
-+                              extern int cmd640_vlb; /* flag for cmd640.c */
-+                              cmd640_vlb = 1;
-+                              goto done;
-+                      }
-+#endif
-+#ifdef CONFIG_BLK_DEV_HT6560B
-+                      case -13: /* "ht6560b" */
-+                              probe_ht6560b = 1;
-+                              goto done;
-+#endif
-+#ifdef CONFIG_BLK_DEV_QD65XX
-+                      case -12: /* "qd65xx" */
-+                              probe_qd65xx = 1;
-+                              goto done;
-+#endif
-+#ifdef CONFIG_BLK_DEV_4DRIVES
-+                      case -11: /* "four" drives on one set of ports */
-+                      {
-+                              ide_hwif_t *mate = &ide_hwifs[hw^1];
-+                              mate->drives[0].select.all ^= 0x20;
-+                              mate->drives[1].select.all ^= 0x20;
-+                              hwif->chipset = mate->chipset = ide_4drives;
-+                              mate->irq = hwif->irq;
-+                              memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
-+                              goto do_serialize;
-+                      }
-+#endif /* CONFIG_BLK_DEV_4DRIVES */
-+                      case -10: /* minus10 */
-+                      case -9: /* minus9 */
-+                      case -8: /* minus8 */
-+                              goto bad_option;
-+                      case -7: /* ata66 */
-+#ifdef CONFIG_BLK_DEV_IDEPCI
-+                              hwif->udma_four = 1;
-+                              goto obsolete_option;
-+#else
-+                              goto bad_hwif;
-+#endif
-+                      case -6: /* dma */
-+                              hwif->autodma = 1;
-+                              goto obsolete_option;
-+                      case -5: /* "reset" */
-+                              hwif->reset = 1;
-+                              goto obsolete_option;
-+                      case -4: /* "noautotune" */
-+                              hwif->drives[0].autotune = IDE_TUNE_NOAUTO;
-+                              hwif->drives[1].autotune = IDE_TUNE_NOAUTO;
-+                              goto obsolete_option;
-+                      case -3: /* "autotune" */
-+                              hwif->drives[0].autotune = IDE_TUNE_AUTO;
-+                              hwif->drives[1].autotune = IDE_TUNE_AUTO;
-+                              goto obsolete_option;
-+                      case -2: /* "serialize" */
-+                      do_serialize:
-+                              hwif->mate = &ide_hwifs[hw^1];
-+                              hwif->mate->mate = hwif;
-+                              hwif->serialized = hwif->mate->serialized = 1;
-+                              goto obsolete_option;
-+
-+                      case -1: /* "noprobe" */
-+                              hwif->noprobe = 1;
-+                              goto done;
-+
-+                      case 1: /* base */
-+                              vals[1] = vals[0] + 0x206; /* default ctl */
-+                      case 2: /* base,ctl */
-+                              vals[2] = 0;    /* default irq = probe for it */
-+                      case 3: /* base,ctl,irq */
-+                              hwif->hw.irq = vals[2];
-+                              ide_init_hwif_ports(&hwif->hw, (unsigned long) vals[0], (unsigned long) vals[1], &hwif->irq);
-+                              memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-+                              hwif->irq      = vals[2];
-+                              hwif->noprobe  = 0;
-+                              hwif->chipset  = ide_forced;
-+                              goto obsolete_option;
-+
-+                      case 0: goto bad_option;
-+                      default:
-+                              printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
-+                              return 1;
-+              }
-+      }
-+bad_option:
-+      printk(" -- BAD OPTION\n");
-+      return 1;
-+obsolete_option:
-+      printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n");
-+      return 1;
-+bad_hwif:
-+      printk("-- NOT SUPPORTED ON ide%d", hw);
-+done:
-+      printk("\n");
-+      return 1;
-+}
-+
-+extern void pnpide_init(void);
-+extern void h8300_ide_init(void);
-+
-+/*
-+ * probe_for_hwifs() finds/initializes "known" IDE interfaces
-+ */
-+static void __init probe_for_hwifs (void)
-+{
-+#ifdef CONFIG_BLK_DEV_IDEPCI
-+      ide_scan_pcibus(ide_scan_direction);
-+#endif /* CONFIG_BLK_DEV_IDEPCI */
-+
-+#ifdef CONFIG_ETRAX_IDE
-+      {
-+              extern void init_e100_ide(void);
-+              init_e100_ide();
-+      }
-+#endif /* CONFIG_ETRAX_IDE */
-+#ifdef CONFIG_BLK_DEV_CMD640
-+      {
-+              extern void ide_probe_for_cmd640x(void);
-+              ide_probe_for_cmd640x();
-+      }
-+#endif /* CONFIG_BLK_DEV_CMD640 */
-+#ifdef CONFIG_BLK_DEV_IDE_PMAC
-+      {
-+              extern void pmac_ide_probe(void);
-+              pmac_ide_probe();
-+      }
-+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-+#ifdef CONFIG_BLK_DEV_GAYLE
-+      {
-+              extern void gayle_init(void);
-+              gayle_init();
-+      }
-+#endif /* CONFIG_BLK_DEV_GAYLE */
-+#ifdef CONFIG_BLK_DEV_FALCON_IDE
-+      {
-+              extern void falconide_init(void);
-+              falconide_init();
-+      }
-+#endif /* CONFIG_BLK_DEV_FALCON_IDE */
-+#ifdef CONFIG_BLK_DEV_MAC_IDE
-+      {
-+              extern void macide_init(void);
-+              macide_init();
-+      }
-+#endif /* CONFIG_BLK_DEV_MAC_IDE */
-+#ifdef CONFIG_BLK_DEV_Q40IDE
-+      {
-+              extern void q40ide_init(void);
-+              q40ide_init();
-+      }
-+#endif /* CONFIG_BLK_DEV_Q40IDE */
-+#ifdef CONFIG_BLK_DEV_BUDDHA
-+      {
-+              extern void buddha_init(void);
-+              buddha_init();
-+      }
-+#endif /* CONFIG_BLK_DEV_BUDDHA */
-+#ifdef CONFIG_BLK_DEV_IDEPNP
-+      pnpide_init();
-+#endif
-+#ifdef CONFIG_H8300
-+      h8300_ide_init();
-+#endif
-+}
-+
-+void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-+{
-+#ifdef CONFIG_PROC_FS
-+      ide_add_proc_entries(drive->proc, driver->proc, drive);
-+#endif
-+}
-+
-+EXPORT_SYMBOL(ide_register_subdriver);
-+
-+/**
-+ *    ide_unregister_subdriver        -       disconnect drive from driver
-+ *    @drive: drive to unplug
-+ *    @driver: driver
-+ *
-+ *    Disconnect a drive from the driver it was attached to and then
-+ *    clean up the various proc files and other objects attached to it.
-+ *
-+ *    Takes ide_setting_sem and ide_lock.
-+ *    Caller must hold none of the locks.
-+ */
-+
-+void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-+{
-+      unsigned long flags;
-+      
-+      down(&ide_setting_sem);
-+      spin_lock_irqsave(&ide_lock, flags);
-+#ifdef CONFIG_PROC_FS
-+      ide_remove_proc_entries(drive->proc, driver->proc);
-+#endif
-+      auto_remove_settings(drive);
-+      spin_unlock_irqrestore(&ide_lock, flags);
-+      up(&ide_setting_sem);
-+}
-+
-+EXPORT_SYMBOL(ide_unregister_subdriver);
-+
-+/*
-+ * Probe module
-+ */
-+
-+EXPORT_SYMBOL(ide_lock);
-+
-+static int ide_bus_match(struct device *dev, struct device_driver *drv)
-+{
-+      return 1;
-+}
-+
-+static char *media_string(ide_drive_t *drive)
-+{
-+      switch (drive->media) {
-+      case ide_disk:
-+              return "disk";
-+      case ide_cdrom:
-+              return "cdrom";
-+      case ide_tape:
-+              return "tape";
-+      case ide_floppy:
-+              return "floppy";
-+      default:
-+              return "UNKNOWN";
-+      }
-+}
-+
-+static ssize_t media_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+      ide_drive_t *drive = to_ide_device(dev);
-+      return sprintf(buf, "%s\n", media_string(drive));
-+}
-+
-+static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+      ide_drive_t *drive = to_ide_device(dev);
-+      return sprintf(buf, "%s\n", drive->name);
-+}
-+
-+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+      ide_drive_t *drive = to_ide_device(dev);
-+      return sprintf(buf, "ide:m-%s\n", media_string(drive));
-+}
-+
-+static struct device_attribute ide_dev_attrs[] = {
-+      __ATTR_RO(media),
-+      __ATTR_RO(drivename),
-+      __ATTR_RO(modalias),
-+      __ATTR_NULL
-+};
-+
-+static int ide_uevent(struct device *dev, char **envp, int num_envp,
-+                    char *buffer, int buffer_size)
-+{
-+      ide_drive_t *drive = to_ide_device(dev);
-+      int i = 0;
-+      int length = 0;
-+
-+      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+                     "MEDIA=%s", media_string(drive));
-+      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+                     "DRIVENAME=%s", drive->name);
-+      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+                     "MODALIAS=ide:m-%s", media_string(drive));
-+      envp[i] = NULL;
-+      return 0;
-+}
-+
-+static int generic_ide_probe(struct device *dev)
-+{
-+      ide_drive_t *drive = to_ide_device(dev);
-+      ide_driver_t *drv = to_ide_driver(dev->driver);
-+
-+      return drv->probe ? drv->probe(drive) : -ENODEV;
-+}
-+
-+static int generic_ide_remove(struct device *dev)
-+{
-+      ide_drive_t *drive = to_ide_device(dev);
-+      ide_driver_t *drv = to_ide_driver(dev->driver);
-+
-+      if (drv->remove)
-+              drv->remove(drive);
-+
-+      return 0;
-+}
-+
-+static void generic_ide_shutdown(struct device *dev)
-+{
-+      ide_drive_t *drive = to_ide_device(dev);
-+      ide_driver_t *drv = to_ide_driver(dev->driver);
-+
-+      if (dev->driver && drv->shutdown)
-+              drv->shutdown(drive);
-+}
-+
-+struct bus_type ide_bus_type = {
-+      .name           = "ide",
-+      .match          = ide_bus_match,
-+      .uevent         = ide_uevent,
-+      .probe          = generic_ide_probe,
-+      .remove         = generic_ide_remove,
-+      .shutdown       = generic_ide_shutdown,
-+      .dev_attrs      = ide_dev_attrs,
-+      .suspend        = generic_ide_suspend,
-+      .resume         = generic_ide_resume,
-+};
-+
-+EXPORT_SYMBOL_GPL(ide_bus_type);
-+
-+/*
-+ * This is gets invoked once during initialization, to set *everything* up
-+ */
-+static int __init ide_init(void)
-+{
-+      int ret;
-+
-+      printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-+      system_bus_speed = ide_system_bus_speed();
-+
-+      ret = bus_register(&ide_bus_type);
-+      if (ret < 0) {
-+              printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
-+              return ret;
-+      }
-+
-+      init_ide_data();
-+
-+#ifdef CONFIG_PROC_FS
-+      proc_ide_root = proc_mkdir("ide", NULL);
-+#endif
-+
-+#ifdef CONFIG_BLK_DEV_ALI14XX
-+      if (probe_ali14xx)
-+              (void)ali14xx_init();
-+#endif
-+#ifdef CONFIG_BLK_DEV_UMC8672
-+      if (probe_umc8672)
-+              (void)umc8672_init();
-+#endif
-+#ifdef CONFIG_BLK_DEV_DTC2278
-+      if (probe_dtc2278)
-+              (void)dtc2278_init();
-+#endif
-+#ifdef CONFIG_BLK_DEV_HT6560B
-+      if (probe_ht6560b)
-+              (void)ht6560b_init();
-+#endif
-+#ifdef CONFIG_BLK_DEV_QD65XX
-+      if (probe_qd65xx)
-+              (void)qd65xx_init();
-+#endif
-+
-+      initializing = 1;
-+      /* Probe for special PCI and other "known" interface chipsets. */
-+      probe_for_hwifs();
-+      initializing = 0;
-+
-+#ifdef CONFIG_PROC_FS
-+      proc_ide_create();
-+#endif
-+      return 0;
-+}
-+
-+#ifdef MODULE
-+static char *options = NULL;
-+module_param(options, charp, 0);
-+MODULE_LICENSE("GPL");
-+
-+static void __init parse_options (char *line)
-+{
-+      char *next = line;
-+
-+      if (line == NULL || !*line)
-+              return;
-+      while ((line = next) != NULL) {
-+              if ((next = strchr(line,' ')) != NULL)
-+                      *next++ = 0;
-+              if (!ide_setup(line))
-+                      printk (KERN_INFO "Unknown option '%s'\n", line);
-+      }
-+}
-+
-+int __init init_module (void)
-+{
-+      parse_options(options);
-+      return ide_init();
-+}
-+
-+void cleanup_module (void)
-+{
-+      int index;
-+
-+      for (index = 0; index < MAX_HWIFS; ++index)
-+              ide_unregister(index);
-+
-+#ifdef CONFIG_PROC_FS
-+      proc_ide_destroy();
-+#endif
-+
-+      bus_unregister(&ide_bus_type);
-+}
-+
-+#else /* !MODULE */
-+
-+__setup("", ide_setup);
-+
-+module_init(ide_init);
-+
-+#endif /* MODULE */
 diff -purN linux.old/drivers/ide/Kconfig linux.dev/drivers/ide/Kconfig
 --- linux.old/drivers/ide/Kconfig      2007-01-10 20:10:37.000000000 +0100
 +++ linux.dev/drivers/ide/Kconfig      2007-04-09 01:15:27.570515264 +0200
@@ -2151,156 +48,3 @@ diff -purN linux.old/drivers/ide/Makefile linux.dev/drivers/ide/Makefile
  
  # built-in only drivers from h8300/
  ide-core-$(CONFIG_H8300)              += h8300/ide-h8300.o
-diff -purN linux.old/drivers/ide/ppc/magicbox_ide.c linux.dev/drivers/ide/ppc/magicbox_ide.c
---- linux.old/drivers/ide/ppc/magicbox_ide.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/drivers/ide/ppc/magicbox_ide.c   2007-04-09 01:25:39.119545680 +0200
-@@ -0,0 +1,149 @@
-+/* Driver for MagicBox 2.0 onboard CompactFlash adapter.
-+ * Written by Wojtek Kaniewski <wojtekka@toxygen.net>
-+ *
-+ * GNU General Public License.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/mm.h>
-+#include <linux/interrupt.h>
-+#include <linux/blkdev.h>
-+#include <linux/hdreg.h>
-+#include <linux/ide.h>
-+#include <linux/delay.h>
-+#include <linux/platform_device.h>
-+
-+
-+#define UIC0_PR 0xc4
-+#define UIC0_TR 0xc5
-+#define IRQ 25
-+
-+static int ide_offsets[IDE_NR_PORTS] = {0, 2, 4, 6, 8, 10, 12, 14, -1, -1};
-+
-+static u8 magicbox_ide_inb (unsigned long port)
-+{
-+      return (u8) (readw((void __iomem *) port) >> 8) & 255;
-+}
-+
-+static u16 magicbox_ide_inw (unsigned long port)
-+{
-+      return (u16) readw((void __iomem *) port);
-+}
-+
-+static void magicbox_ide_insw (unsigned long port, void *addr, u32 count)
-+{
-+      u16 *ptr;
-+
-+      for (ptr = addr; count--; ptr++)
-+              *ptr = readw((void __iomem *) port);
-+}
-+
-+static u32 magicbox_ide_inl (unsigned long port)
-+{
-+      return (u32) readl((void __iomem *) port);
-+}
-+
-+static void magicbox_ide_insl (unsigned long port, void *addr, u32 count)
-+{
-+      u32 *ptr;
-+
-+      for (ptr = addr; count--; ptr++)
-+              *ptr = readl((void __iomem *) port);
-+}
-+
-+static void magicbox_ide_outb (u8 value, unsigned long port)
-+{
-+      writew(value << 8, (void __iomem *) port);
-+}
-+
-+static void magicbox_ide_outbsync (ide_drive_t *drive, u8 value, unsigned long port)
-+{
-+      writew(value << 8, (void __iomem *) port);
-+}
-+
-+static void magicbox_ide_outw (u16 value, unsigned long port)
-+{
-+      writew(value, (void __iomem *) port);
-+}
-+
-+static void magicbox_ide_outsw (unsigned long port, void *addr, u32 count)
-+{
-+      u16 *ptr;
-+
-+      for (ptr = addr; count--; ptr++)
-+              writew(*ptr, (void __iomem *) port);
-+}
-+
-+static void magicbox_ide_outl (u32 value, unsigned long port)
-+{
-+      writel(value, (void __iomem *) port);
-+}
-+
-+static void magicbox_ide_outsl (unsigned long port, void *addr, u32 count)
-+{
-+      u32 *ptr;
-+
-+      for (ptr = addr; count--; ptr++)
-+              writel(*ptr, (void __iomem *) port);
-+}
-+
-+
-+static void __init ide_magicbox_register(unsigned long addr,
-+                                       unsigned long caddr, int irq)
-+{
-+      hw_regs_t hw;
-+      ide_hwif_t *hwif;
-+
-+      memset(&hw, 0, sizeof(hw));
-+      ide_setup_ports(&hw, addr, ide_offsets, caddr + 12, 0, NULL,irq);
-+
-+      if (ide_register_hw(&hw, &hwif) != -1)
-+      {
-+              printk(KERN_NOTICE "magicbox-ide: Registered IDE-CF driver\n");
-+              hwif->mmio = 2;
-+              hwif->drives[0].unmask = 1;
-+              hwif->OUTB = magicbox_ide_outb;
-+              hwif->OUTBSYNC = magicbox_ide_outbsync;
-+              hwif->OUTW = magicbox_ide_outw;
-+              hwif->OUTL = magicbox_ide_outl;
-+              hwif->OUTSW = magicbox_ide_outsw;
-+              hwif->OUTSL = magicbox_ide_outsl;
-+              hwif->INB = magicbox_ide_inb;
-+              hwif->INW = magicbox_ide_inw;
-+              hwif->INL = magicbox_ide_inl;
-+              hwif->INSW = magicbox_ide_insw;
-+              hwif->INSL = magicbox_ide_insl;
-+      }
-+}
-+
-+void __init ide_magicbox_init(void)
-+{
-+      volatile u16 *addr;
-+      volatile u16 *caddr;
-+
-+      /* Turn on PerWE instead of PCIsomething */
-+      mtdcr(DCRN_CPC0_PCI_BASE, mfdcr(DCRN_CPC0_PCI_BASE) | (0x80000000L >> 27));
-+
-+      /* PerCS1 (CF's CS0): base 0xff100000, 16-bit, rw */
-+      mtdcr(DCRN_EBC_BASE, 1);
-+      mtdcr(DCRN_EBC_BASE + 1, 0xff11a000);
-+      mtdcr(DCRN_EBC_BASE, 0x11);
-+      mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
-+
-+      /* PerCS2 (CF's CS1): base 0xff200000, 16-bit, rw */
-+      mtdcr(DCRN_EBC_BASE, 2);
-+      mtdcr(DCRN_EBC_BASE + 1, 0xff21a000);
-+      mtdcr(DCRN_EBC_BASE, 0x12);
-+      mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
-+
-+      /* Remap physical address space */
-+      addr = ioremap_nocache(0xff100000, 4096);
-+      caddr = ioremap_nocache(0xff200000, 4096);
-+
-+      /* Set interrupt to low-to-high-edge-triggered */
-+      mtdcr(UIC0_TR, mfdcr(UIC0_TR) & ~(0x80000000L >> IRQ));
-+      mtdcr(UIC0_PR, mfdcr(UIC0_PR) | (0x80000000L >> IRQ));
-+
-+      ide_magicbox_register((unsigned long)addr, (unsigned long)caddr, IRQ);
-+}
-+