diff options
8 files changed, 566 insertions, 2683 deletions
diff --git a/target/linux/generic-2.6/config-template b/target/linux/generic-2.6/config-template index 1c1d57077d..d06096ee2d 100644 --- a/target/linux/generic-2.6/config-template +++ b/target/linux/generic-2.6/config-template @@ -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 index 0000000000..470fbc4e08 --- /dev/null +++ b/target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.c @@ -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 index 0000000000..6ce1e5b8ce --- /dev/null +++ b/target/linux/magicbox-2.6/files/arch/ppc/platforms/4xx/magicbox.h @@ -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 index 0000000000..d1f6d68edb --- /dev/null +++ b/target/linux/magicbox-2.6/files/drivers/ide/ppc/magicbox_ide.c @@ -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 index 0000000000..b654a3d9bd --- /dev/null +++ b/target/linux/magicbox-2.6/files/drivers/mtd/maps/magicmap.c @@ -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 --git a/target/linux/magicbox-2.6/patches/001-magicbox_support.patch b/target/linux/magicbox-2.6/patches/001-magicbox_support.patch index 7c609e5d02..873160d3bc 100644 --- a/target/linux/magicbox-2.6/patches/001-magicbox_support.patch +++ b/target/linux/magicbox-2.6/patches/001-magicbox_support.patch @@ -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 diff --git a/target/linux/magicbox-2.6/patches/002-flash_map.patch b/target/linux/magicbox-2.6/patches/002-flash_map.patch index 5d29a047d5..415daa51b5 100644 --- a/target/linux/magicbox-2.6/patches/002-flash_map.patch +++ b/target/linux/magicbox-2.6/patches/002-flash_map.patch @@ -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 diff --git a/target/linux/magicbox-2.6/patches/100-cf_slot.patch b/target/linux/magicbox-2.6/patches/100-cf_slot.patch index b5e12438f2..490cfca665 100644 --- a/target/linux/magicbox-2.6/patches/100-cf_slot.patch +++ b/target/linux/magicbox-2.6/patches/100-cf_slot.patch @@ -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); -+} -+ |