提交 a48178a2 编写于 作者: L Linus Torvalds

Merge git://git.infradead.org/mtd-2.6

* git://git.infradead.org/mtd-2.6:
  Remove accidentally-added include/linux/utsrelease.h
  Revert "[MTD] blkdev helper code: fix printk format warning"
  [MTD] Add SSFDC (SmartMedia) read-only translation layer
  [MTD] pmc551 pci cleanup
  [MTD] pmc551 use kzalloc
  [MTD] pmc551 whitespace cleanup
  [MTD] Remove iq80310 map driver
  [MTD NAND] Fix in typo ndfc.c causing wrong ECC layout
  [MTD] physmap: add power management support
  ioremap balanced with iounmap for drivers/mtd subsystem
  [MTD] Switch to pci_get_device and do ref counting
  [MTD] blkdev helper code: fix printk format warning
  [MTD] Fix ixp4xx partition parsing.
  [JFFS2] Remove unneeded ifdefs from jffs2_fs_i.h
  [MTD NAND] Remove old code in au1550nd.c
  [MTD] Unlock NOR flash automatically where necessary
......@@ -263,6 +263,14 @@ config RFD_FTL
http://www.gensw.com/pages/prod/bios/rfd.htm
config SSFDC
bool "NAND SSFDC (SmartMedia) read only translation layer"
depends on MTD
default n
help
This enables read only access to SmartMedia formatted NAND
flash. You can mount it with FAT file system.
source "drivers/mtd/chips/Kconfig"
source "drivers/mtd/maps/Kconfig"
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o
obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o
obj-$(CONFIG_SSFDC) += ssfdc.o mtd_blkdevs.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
......
......@@ -212,6 +212,7 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
{
mtd->lock = cfi_atmel_lock;
mtd->unlock = cfi_atmel_unlock;
mtd->flags |= MTD_STUPID_LOCK;
}
static struct cfi_fixup cfi_fixup_table[] = {
......
此差异已折叠。
......@@ -447,14 +447,6 @@ config MTD_DC21285
21285 bridge used with Intel's StrongARM processors. More info at
<http://www.intel.com/design/bridge/docs/21285_documentation.htm>.
config MTD_IQ80310
tristate "CFI Flash device mapped on the XScale IQ80310 board"
depends on MTD_CFI && ARCH_IQ80310
help
This enables access routines for the flash chips on the Intel XScale
IQ80310 evaluation board. If you have one of these boards and would
like to use the flash chips on it, say 'Y'.
config MTD_IXP4XX
tristate "CFI Flash device mapped on Intel IXP4xx based systems"
depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
......
......@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
......
......@@ -57,6 +57,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
/* Disable writes through the rom window */
pci_read_config_byte(window->pdev, 0x40, &byte);
pci_write_config_byte(window->pdev, 0x40, byte & ~1);
pci_dev_put(window->pdev);
}
/* Free all of the mtd devices */
......@@ -91,7 +92,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
struct amd76xrom_map_info *map = NULL;
unsigned long map_top;
/* Remember the pci dev I find the window in */
/* Remember the pci dev I find the window in - already have a ref */
window->pdev = pdev;
/* Assume the rom window is properly setup, and find it's size */
......@@ -302,7 +303,7 @@ static int __init init_amd76xrom(void)
struct pci_device_id *id;
pdev = NULL;
for(id = amd76xrom_pci_tbl; id->vendor; id++) {
pdev = pci_find_device(id->vendor, id->device, NULL);
pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev) {
break;
}
......
......@@ -96,6 +96,8 @@ static struct mtd_partition arctic_partitions[PARTITIONS] = {
static int __init
init_arctic_mtd(void)
{
int err = 0;
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
arctic_mtd_map.virt = ioremap(PADDR, SIZE);
......@@ -109,12 +111,20 @@ init_arctic_mtd(void)
printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
if (!arctic_mtd)
if (!arctic_mtd) {
iounmap((void *) arctic_mtd_map.virt);
return -ENXIO;
}
arctic_mtd->owner = THIS_MODULE;
return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
if (err) {
printk("%s: add_mtd_partitions failed\n", NAME);
iounmap((void *) arctic_mtd_map.virt);
}
return err;
}
static void __exit
......
......@@ -72,6 +72,8 @@ static struct mtd_partition beech_partitions[2] = {
static int __init
init_beech_mtd(void)
{
int err = 0;
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
beech_mtd_map.virt = ioremap(PADDR, SIZE);
......@@ -86,12 +88,20 @@ init_beech_mtd(void)
printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
if (!beech_mtd)
if (!beech_mtd) {
iounmap((void *) beech_mtd_map.virt);
return -ENXIO;
}
beech_mtd->owner = THIS_MODULE;
return add_mtd_partitions(beech_mtd, beech_partitions, 2);
err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
if (err) {
printk("%s: add_mtd_partitions failed\n", NAME);
iounmap((void *) beech_mtd_map.virt);
}
return err;
}
static void __exit
......
......@@ -171,7 +171,14 @@ int __init init_cstm_mips_ixx(void)
cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
if (!cstm_mips_ixx_map[i].virt) {
int j = 0;
printk(KERN_WARNING "Failed to ioremap\n");
for (j = 0; j < i; j++) {
if (cstm_mips_ixx_map[j].virt) {
iounmap((void *)cstm_mips_ixx_map[j].virt);
cstm_mips_ixx_map[j].virt = 0;
}
}
return -EIO;
}
cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
......@@ -204,8 +211,15 @@ int __init init_cstm_mips_ixx(void)
cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
}
else
return -ENXIO;
else {
for (i = 0; i < PHYSMAP_NUMBER; i++) {
if (cstm_mips_ixx_map[i].virt) {
iounmap((void *)cstm_mips_ixx_map[i].virt);
cstm_mips_ixx_map[i].virt = 0;
}
}
return -ENXIO;
}
}
return 0;
}
......
......@@ -108,6 +108,7 @@ int __init init_ebony(void)
ARRAY_SIZE(ebony_small_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ebony_small_map.virt);
return -ENXIO;
}
......@@ -117,6 +118,7 @@ int __init init_ebony(void)
if (!ebony_large_map.virt) {
printk("Failed to ioremap flash\n");
iounmap(ebony_small_map.virt);
return -EIO;
}
......@@ -129,6 +131,8 @@ int __init init_ebony(void)
ARRAY_SIZE(ebony_large_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ebony_small_map.virt);
iounmap(ebony_large_map.virt);
return -ENXIO;
}
......
......@@ -218,8 +218,11 @@ int __init init_fortunet(void)
map_regions[ix].map_info.size);
if(!map_regions[ix].map_info.virt)
{
int j = 0;
printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
map_regions[ix].map_info.name);
for (j = 0 ; j < ix; j++)
iounmap(map_regions[j].map_info.virt);
return -ENXIO;
}
simple_map_init(&map_regions[ix].map_info);
......
......@@ -61,6 +61,7 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
/* Disable writes through the rom window */
pci_read_config_word(window->pdev, BIOS_CNTL, &word);
pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
pci_dev_put(window->pdev);
/* Free all of the mtd devices */
list_for_each_entry_safe(map, scratch, &window->maps, list) {
......@@ -355,7 +356,7 @@ static int __init init_ichxrom(void)
pdev = NULL;
for (id = ichxrom_pci_tbl; id->vendor; id++) {
pdev = pci_find_device(id->vendor, id->device, NULL);
pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev) {
break;
}
......
/*
* $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
*
* Mapping for the Intel XScale IQ80310 evaluation board
*
* Author: Nicolas Pitre
* Copyright: (C) 2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#define WINDOW_ADDR 0
#define WINDOW_SIZE 8*1024*1024
#define BUSWIDTH 1
static struct mtd_info *mymtd;
static struct map_info iq80310_map = {
.name = "IQ80310 flash",
.size = WINDOW_SIZE,
.bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR
};
static struct mtd_partition iq80310_partitions[4] = {
{
.name = "Firmware",
.size = 0x00080000,
.offset = 0,
.mask_flags = MTD_WRITEABLE /* force read-only */
},{
.name = "Kernel",
.size = 0x000a0000,
.offset = 0x00080000,
},{
.name = "Filesystem",
.size = 0x00600000,
.offset = 0x00120000
},{
.name = "RedBoot",
.size = 0x000e0000,
.offset = 0x00720000,
.mask_flags = MTD_WRITEABLE
}
};
static struct mtd_info *mymtd;
static struct mtd_partition *parsed_parts;
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static int __init init_iq80310(void)
{
struct mtd_partition *parts;
int nb_parts = 0;
int parsed_nr_parts = 0;
int ret;
iq80310_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!iq80310_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
simple_map_init(&iq80310_map);
mymtd = do_map_probe("cfi_probe", &iq80310_map);
if (!mymtd) {
iounmap((void *)iq80310_map.virt);
return -ENXIO;
}
mymtd->owner = THIS_MODULE;
ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
if (ret > 0)
parsed_nr_parts = ret;
if (parsed_nr_parts > 0) {
parts = parsed_parts;
nb_parts = parsed_nr_parts;
} else {
parts = iq80310_partitions;
nb_parts = ARRAY_SIZE(iq80310_partitions);
}
add_mtd_partitions(mymtd, parts, nb_parts);
return 0;
}
static void __exit cleanup_iq80310(void)
{
if (mymtd) {
del_mtd_partitions(mymtd);
map_destroy(mymtd);
kfree(parsed_parts);
}
if (iq80310_map.virt)
iounmap((void *)iq80310_map.virt);
}
module_init(init_iq80310);
module_exit(cleanup_iq80310);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
MODULE_DESCRIPTION("MTD map driver for Intel XScale IQ80310 evaluation board");
......@@ -253,7 +253,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
/* Use the fast version */
info->map.write = ixp4xx_write16,
err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
err = parse_mtd_partitions(info->mtd, probes, &info->partitions, dev->resource->start);
if (err > 0) {
err = add_mtd_partitions(info->mtd, info->partitions, err);
if(err)
......
......@@ -61,14 +61,17 @@ static int __init init_l440gx(void)
struct resource *pm_iobase;
__u16 word;
dev = pci_find_device(PCI_VENDOR_ID_INTEL,
dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
pm_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
pci_dev_put(dev);
if (!dev || !pm_dev) {
printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n");
pci_dev_put(pm_dev);
return -ENODEV;
}
......@@ -76,6 +79,7 @@ static int __init init_l440gx(void)
if (!l440gx_map.virt) {
printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
pci_dev_put(pm_dev);
return -ENOMEM;
}
simple_map_init(&l440gx_map);
......@@ -99,8 +103,12 @@ static int __init init_l440gx(void)
pm_iobase->start += iobase & ~1;
pm_iobase->end += iobase & ~1;
pci_dev_put(pm_dev);
/* Allocate the resource region */
if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
pci_dev_put(dev);
pci_dev_put(pm_dev);
printk(KERN_WARNING "Could not allocate pm iobase resource\n");
iounmap(l440gx_map.virt);
return -ENXIO;
......
......@@ -79,6 +79,7 @@ static int __init init_lasat(void)
return 0;
}
iounmap(lasat_map.virt);
return -ENXIO;
}
......@@ -89,6 +90,7 @@ static void __exit cleanup_lasat(void)
map_destroy(lasat_mtd);
}
if (lasat_map.virt) {
iounmap(lasat_map.virt);
lasat_map.virt = 0;
}
}
......
......@@ -277,6 +277,7 @@ int __init nettel_init(void)
nettel_amd_map.virt = ioremap_nocache(amdaddr, maxsize);
if (!nettel_amd_map.virt) {
printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
iounmap(nettel_mmcrp);
return(-EIO);
}
simple_map_init(&nettel_amd_map);
......@@ -337,7 +338,8 @@ int __init nettel_init(void)
nettel_amd_map.virt = NULL;
#else
/* Only AMD flash supported */
return(-ENXIO);
rc = -ENXIO;
goto out_unmap2;
#endif
}
......@@ -361,14 +363,15 @@ int __init nettel_init(void)
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
return(-EIO);
rc = -EIO;
goto out_unmap2;
}
simple_map_init(&nettel_intel_map);
intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
if (!intel_mtd) {
iounmap(nettel_intel_map.virt);
return(-ENXIO);
rc = -ENXIO;
goto out_unmap1;
}
/* Set PAR to the detected size */
......@@ -394,13 +397,14 @@ int __init nettel_init(void)
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
return(-EIO);
rc = -EIO;
goto out_unmap2;
}
intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
if (! intel_mtd) {
iounmap((void *) nettel_intel_map.virt);
return(-ENXIO);
rc = -ENXIO;
goto out_unmap1;
}
intel1size = intel_mtd->size - intel0size;
......@@ -456,6 +460,18 @@ int __init nettel_init(void)
#endif
return(rc);
#ifdef CONFIG_MTD_CFI_INTELEXT
out_unmap1:
iounmap((void *) nettel_intel_map.virt);
#endif
out_unmap2:
iounmap(nettel_mmcrp);
iounmap(nettel_amd_map.virt);
return(rc);
}
/****************************************************************************/
......@@ -469,6 +485,10 @@ void __exit nettel_cleanup(void)
del_mtd_partitions(amd_mtd);
map_destroy(amd_mtd);
}
if (nettel_mmcrp) {
iounmap(nettel_mmcrp);
nettel_mmcrp = NULL;
}
if (nettel_amd_map.virt) {
iounmap(nettel_amd_map.virt);
nettel_amd_map.virt = NULL;
......
......@@ -97,6 +97,7 @@ int __init init_ocotea(void)
ARRAY_SIZE(ocotea_small_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ocotea_small_map.virt);
return -ENXIO;
}
......@@ -106,6 +107,7 @@ int __init init_ocotea(void)
if (!ocotea_large_map.virt) {
printk("Failed to ioremap flash\n");
iounmap(ocotea_small_map.virt);
return -EIO;
}
......@@ -118,6 +120,8 @@ int __init init_ocotea(void)
ARRAY_SIZE(ocotea_large_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ocotea_small_map.virt);
iounmap(ocotea_large_map.virt);
return -ENXIO;
}
......
......@@ -602,6 +602,10 @@ static int pcmciamtd_config(struct pcmcia_device *link)
ret = pcmcia_request_configuration(link, &link->conf);
if(ret != CS_SUCCESS) {
cs_error(link, RequestConfiguration, ret);
if (dev->win_base) {
iounmap(dev->win_base);
dev->win_base = NULL;
}
return -ENODEV;
}
......
......@@ -158,9 +158,42 @@ static int physmap_flash_probe(struct platform_device *dev)
return err;
}
#ifdef CONFIG_PM
static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state)
{
struct physmap_flash_info *info = platform_get_drvdata(dev);
int ret = 0;
if (info)
ret = info->mtd->suspend(info->mtd);
return ret;
}
static int physmap_flash_resume(struct platform_device *dev)
{
struct physmap_flash_info *info = platform_get_drvdata(dev);
if (info)
info->mtd->resume(info->mtd);
return 0;
}
static void physmap_flash_shutdown(struct platform_device *dev)
{
struct physmap_flash_info *info = platform_get_drvdata(dev);
if (info && info->mtd->suspend(info->mtd) == 0)
info->mtd->resume(info->mtd);
}
#endif
static struct platform_driver physmap_flash_driver = {
.probe = physmap_flash_probe,
.remove = physmap_flash_remove,
#ifdef CONFIG_PM
.suspend = physmap_flash_suspend,
.resume = physmap_flash_resume,
.shutdown = physmap_flash_shutdown,
#endif
.driver = {
.name = "physmap-flash",
},
......
......@@ -126,6 +126,8 @@ static struct mtd_info *redwood_mtd;
int __init init_redwood_flash(void)
{
int err = 0;
printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
WINDOW_SIZE, WINDOW_ADDR);
......@@ -141,11 +143,18 @@ int __init init_redwood_flash(void)
if (redwood_mtd) {
redwood_mtd->owner = THIS_MODULE;
return add_mtd_partitions(redwood_mtd,
err = add_mtd_partitions(redwood_mtd,
redwood_flash_partitions,
NUM_REDWOOD_FLASH_PARTITIONS);
if (err) {
printk("init_redwood_flash: add_mtd_partitions failed\n");
iounmap(redwood_flash_map.virt);
}
return err;
}
iounmap(redwood_flash_map.virt);
return -ENXIO;
}
......
......@@ -156,7 +156,7 @@ int __init init_sbc8240_mtd (void)
};
int devicesfound = 0;
int i;
int i,j;
for (i = 0; i < NUM_FLASH_BANKS; i++) {
printk (KERN_NOTICE MSG_PREFIX
......@@ -166,6 +166,10 @@ int __init init_sbc8240_mtd (void)
(unsigned long) ioremap (pt[i].addr, pt[i].size);
if (!sbc8240_map[i].map_priv_1) {
printk (MSG_PREFIX "failed to ioremap\n");
for (j = 0; j < i; j++) {
iounmap((void *) sbc8240_map[j].map_priv_1);
sbc8240_map[j].map_priv_1 = 0;
}
return -EIO;
}
simple_map_init(&sbc8240_mtd[i]);
......@@ -175,6 +179,11 @@ int __init init_sbc8240_mtd (void)
if (sbc8240_mtd[i]) {
sbc8240_mtd[i]->module = THIS_MODULE;
devicesfound++;
} else {
if (sbc8240_map[i].map_priv_1) {
iounmap((void *) sbc8240_map[i].map_priv_1);
sbc8240_map[i].map_priv_1 = 0;
}
}
}
......
......@@ -87,19 +87,23 @@ static int __init init_scx200_docflash(void)
printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
if ((bridge = pci_find_device(PCI_VENDOR_ID_NS,
if ((bridge = pci_get_device(PCI_VENDOR_ID_NS,
PCI_DEVICE_ID_NS_SCx200_BRIDGE,
NULL)) == NULL)
return -ENODEV;
/* check that we have found the configuration block */
if (!scx200_cb_present())
if (!scx200_cb_present()) {
pci_dev_put(bridge);
return -ENODEV;
}
if (probe) {
/* Try to use the present flash mapping if any */
pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
pci_dev_put(bridge);
pmr = inl(scx200_cb_base + SCx200_PMR);
if (base == 0
......@@ -127,6 +131,7 @@ static int __init init_scx200_docflash(void)
return -ENOMEM;
}
} else {
pci_dev_put(bridge);
for (u = size; u > 1; u >>= 1)
;
if (u != 1) {
......
......@@ -68,6 +68,7 @@ int __init init_walnut(void)
if (WALNUT_FLASH_ONBD_N(fpga_brds1)) {
printk("The on-board flash is disabled (U79 sw 5)!");
iounmap(fpga_status_adr);
return -EIO;
}
if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
......@@ -81,6 +82,7 @@ int __init init_walnut(void)
if (!walnut_map.virt) {
printk("Failed to ioremap flash.\n");
iounmap(fpga_status_adr);
return -EIO;
}
......@@ -93,9 +95,11 @@ int __init init_walnut(void)
ARRAY_SIZE(walnut_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(fpga_status_adr);
return -ENXIO;
}
iounmap(fpga_status_adr);
return 0;
}
......
......@@ -57,6 +57,16 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->index = i;
mtd->usecount = 0;
/* Some chips always power up locked. Unlock them now */
if ((mtd->flags & MTD_WRITEABLE)
&& (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
if (mtd->unlock(mtd, 0, mtd->size))
printk(KERN_WARNING
"%s: unlock failed, "
"writes may not work\n",
mtd->name);
}
DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
/* No need to get a refcount on the module containing
the notifier, since we hold the mtd_table_mutex */
......
......@@ -21,18 +21,7 @@
#include <linux/version.h>
#include <asm/io.h>
/* fixme: this is ugly */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
#include <asm/mach-au1x00/au1xxx.h>
#else
#include <asm/au1000.h>
#ifdef CONFIG_MIPS_PB1550
#include <asm/pb1550.h>
#endif
#ifdef CONFIG_MIPS_DB1550
#include <asm/db1x00.h>
#endif
#endif
/*
* MTD structure for NAND controller
......
......@@ -198,6 +198,9 @@ static void __exit ep7312_cleanup(void)
/* Release resources, unregister device */
nand_release(ap7312_mtd);
/* Release io resource */
iounmap((void *)this->IO_ADDR_R);
/* Free the MTD device structure */
kfree(ep7312_mtd);
}
......
......@@ -168,7 +168,7 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
chip->ecclayout = mtd->pl_chip->ecclayout;
chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
mtd->mtd.priv = chip;
mtd->mtd.owner = THIS_MODULE;
}
......
......@@ -276,6 +276,7 @@ static int __init ppchameleonevb_init(void)
/* Scan to find existence of the device (it could not be mounted) */
if (nand_scan(ppchameleon_mtd, 1)) {
iounmap((void *)ppchameleon_fio_base);
ppchameleon_fio_base = NULL;
kfree(ppchameleon_mtd);
goto nand_evb_init;
}
......@@ -314,6 +315,8 @@ static int __init ppchameleonevb_init(void)
ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ppchameleonevb_mtd) {
printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -ENOMEM;
}
......@@ -322,6 +325,8 @@ static int __init ppchameleonevb_init(void)
if (!ppchameleonevb_fio_base) {
printk("ioremap PPChameleonEVB NAND flash failed\n");
kfree(ppchameleonevb_mtd);
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -EIO;
}
......@@ -378,6 +383,8 @@ static int __init ppchameleonevb_init(void)
if (nand_scan(ppchameleonevb_mtd, 1)) {
iounmap((void *)ppchameleonevb_fio_base);
kfree(ppchameleonevb_mtd);
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -ENXIO;
}
#ifdef CONFIG_MTD_PARTITIONS
......
/*
* Linux driver for SSFDC Flash Translation Layer (Read only)
* (c) 2005 Eptar srl
* Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
*
* Based on NTFL and MTDBLOCK_RO drivers
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/hdreg.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/blktrans.h>
struct ssfdcr_record {
struct mtd_blktrans_dev mbd;
int usecount;
unsigned char heads;
unsigned char sectors;
unsigned short cylinders;
int cis_block; /* block n. containing CIS/IDI */
int erase_size; /* phys_block_size */
unsigned short *logic_block_map; /* all zones (max 8192 phys blocks on
the 128MB) */
int map_len; /* n. phys_blocks on the card */
};
#define SSFDCR_MAJOR 257
#define SSFDCR_PARTN_BITS 3
#define SECTOR_SIZE 512
#define SECTOR_SHIFT 9
#define OOB_SIZE 16
#define MAX_LOGIC_BLK_PER_ZONE 1000
#define MAX_PHYS_BLK_PER_ZONE 1024
#define KB(x) ( (x) * 1024L )
#define MB(x) ( KB(x) * 1024L )
/** CHS Table
1MB 2MB 4MB 8MB 16MB 32MB 64MB 128MB
NCylinder 125 125 250 250 500 500 500 500
NHead 4 4 4 4 4 8 8 16
NSector 4 8 8 16 16 16 32 32
SumSector 2,000 4,000 8,000 16,000 32,000 64,000 128,000 256,000
SectorSize 512 512 512 512 512 512 512 512
**/
typedef struct {
unsigned long size;
unsigned short cyl;
unsigned char head;
unsigned char sec;
} chs_entry_t;
/* Must be ordered by size */
static const chs_entry_t chs_table[] = {
{ MB( 1), 125, 4, 4 },
{ MB( 2), 125, 4, 8 },
{ MB( 4), 250, 4, 8 },
{ MB( 8), 250, 4, 16 },
{ MB( 16), 500, 4, 16 },
{ MB( 32), 500, 8, 16 },
{ MB( 64), 500, 8, 32 },
{ MB(128), 500, 16, 32 },
{ 0 },
};
static int get_chs(unsigned long size, unsigned short *cyl, unsigned char *head,
unsigned char *sec)
{
int k;
int found = 0;
k = 0;
while (chs_table[k].size > 0 && size > chs_table[k].size)
k++;
if (chs_table[k].size > 0) {
if (cyl)
*cyl = chs_table[k].cyl;
if (head)
*head = chs_table[k].head;
if (sec)
*sec = chs_table[k].sec;
found = 1;
}
return found;
}
/* These bytes are the signature for the CIS/IDI sector */
static const uint8_t cis_numbers[] = {
0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20
};
/* Read and check for a valid CIS sector */
static int get_valid_cis_sector(struct mtd_info *mtd)
{
int ret, k, cis_sector;
size_t retlen;
loff_t offset;
uint8_t sect_buf[SECTOR_SIZE];
/*
* Look for CIS/IDI sector on the first GOOD block (give up after 4 bad
* blocks). If the first good block doesn't contain CIS number the flash
* is not SSFDC formatted
*/
cis_sector = -1;
for (k = 0, offset = 0; k < 4; k++, offset += mtd->erasesize) {
if (!mtd->block_isbad(mtd, offset)) {
ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen,
sect_buf);
/* CIS pattern match on the sector buffer */
if ( ret < 0 || retlen != SECTOR_SIZE ) {
printk(KERN_WARNING
"SSFDC_RO:can't read CIS/IDI sector\n");
} else if ( !memcmp(sect_buf, cis_numbers,
sizeof(cis_numbers)) ) {
/* Found */
cis_sector = (int)(offset >> SECTOR_SHIFT);
} else {
DEBUG(MTD_DEBUG_LEVEL1,
"SSFDC_RO: CIS/IDI sector not found"
" on %s (mtd%d)\n", mtd->name,
mtd->index);
}
break;
}
}
return cis_sector;
}
/* Read physical sector (wrapper to MTD_READ) */
static int read_physical_sector(struct mtd_info *mtd, uint8_t *sect_buf,
int sect_no)
{
int ret;
size_t retlen;
loff_t offset = (loff_t)sect_no << SECTOR_SHIFT;
ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen, sect_buf);
if (ret < 0 || retlen != SECTOR_SIZE)
return -1;
return 0;
}
/* Read redundancy area (wrapper to MTD_READ_OOB */
static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)
{
struct mtd_oob_ops ops;
int ret;
ops.mode = MTD_OOB_RAW;
ops.ooboffs = 0;
ops.ooblen = mtd->oobsize;
ops.len = OOB_SIZE;
ops.oobbuf = buf;
ops.datbuf = NULL;
ret = mtd->read_oob(mtd, offs, &ops);
if (ret < 0 || ops.retlen != OOB_SIZE)
return -1;
return 0;
}
/* Parity calculator on a word of n bit size */
static int get_parity(int number, int size)
{
int k;
int parity;
parity = 1;
for (k = 0; k < size; k++) {
parity += (number >> k);
parity &= 1;
}
return parity;
}
/* Read and validate the logical block address field stored in the OOB */
static int get_logical_address(uint8_t *oob_buf)
{
int block_address, parity;
int offset[2] = {6, 11}; /* offset of the 2 address fields within OOB */
int j;
int ok = 0;
/*
* Look for the first valid logical address
* Valid address has fixed pattern on most significant bits and
* parity check
*/
for (j = 0; j < ARRAY_SIZE(offset); j++) {
block_address = ((int)oob_buf[offset[j]] << 8) |
oob_buf[offset[j]+1];
/* Check for the signature bits in the address field (MSBits) */
if ((block_address & ~0x7FF) == 0x1000) {
parity = block_address & 0x01;
block_address &= 0x7FF;
block_address >>= 1;
if (get_parity(block_address, 10) != parity) {
DEBUG(MTD_DEBUG_LEVEL0,
"SSFDC_RO: logical address field%d"
"parity error(0x%04X)\n", j+1,
block_address);
} else {
ok = 1;
break;
}
}
}
if ( !ok )
block_address = -2;
DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n",
block_address);
return block_address;
}
/* Build the logic block map */
static int build_logical_block_map(struct ssfdcr_record *ssfdc)
{
unsigned long offset;
uint8_t oob_buf[OOB_SIZE];
int ret, block_address, phys_block;
struct mtd_info *mtd = ssfdc->mbd.mtd;
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n",
ssfdc->map_len, (unsigned long)ssfdc->map_len *
ssfdc->erase_size / 1024 );
/* Scan every physical block, skip CIS block */
for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len;
phys_block++) {
offset = (unsigned long)phys_block * ssfdc->erase_size;
if (mtd->block_isbad(mtd, offset))
continue; /* skip bad blocks */
ret = read_raw_oob(mtd, offset, oob_buf);
if (ret < 0) {
DEBUG(MTD_DEBUG_LEVEL0,
"SSFDC_RO: mtd read_oob() failed at %lu\n",
offset);
return -1;
}
block_address = get_logical_address(oob_buf);
/* Skip invalid addresses */
if (block_address >= 0 &&
block_address < MAX_LOGIC_BLK_PER_ZONE) {
int zone_index;
zone_index = phys_block / MAX_PHYS_BLK_PER_ZONE;
block_address += zone_index * MAX_LOGIC_BLK_PER_ZONE;
ssfdc->logic_block_map[block_address] =
(unsigned short)phys_block;
DEBUG(MTD_DEBUG_LEVEL2,
"SSFDC_RO: build_block_map() phys_block=%d,"
"logic_block_addr=%d, zone=%d\n",
phys_block, block_address, zone_index);
}
}
return 0;
}
static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
struct ssfdcr_record *ssfdc;
int cis_sector;
/* Check for small page NAND flash */
if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE)
return;
/* Check for SSDFC format by reading CIS/IDI sector */
cis_sector = get_valid_cis_sector(mtd);
if (cis_sector == -1)
return;
ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL);
if (!ssfdc) {
printk(KERN_WARNING
"SSFDC_RO: out of memory for data structures\n");
return;
}
ssfdc->mbd.mtd = mtd;
ssfdc->mbd.devnum = -1;
ssfdc->mbd.blksize = SECTOR_SIZE;
ssfdc->mbd.tr = tr;
ssfdc->mbd.readonly = 1;
ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
ssfdc->erase_size = mtd->erasesize;
ssfdc->map_len = mtd->size / mtd->erasesize;
DEBUG(MTD_DEBUG_LEVEL1,
"SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,
(ssfdc->map_len + MAX_PHYS_BLK_PER_ZONE - 1) /
MAX_PHYS_BLK_PER_ZONE);
/* Set geometry */
ssfdc->heads = 16;
ssfdc->sectors = 32;
get_chs( mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) /
((long)ssfdc->sectors * (long)ssfdc->heads));
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
ssfdc->cylinders, ssfdc->heads , ssfdc->sectors,
(long)ssfdc->cylinders * (long)ssfdc->heads *
(long)ssfdc->sectors );
ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders *
(long)ssfdc->sectors;
/* Allocate logical block map */
ssfdc->logic_block_map = kmalloc( sizeof(ssfdc->logic_block_map[0]) *
ssfdc->map_len, GFP_KERNEL);
if (!ssfdc->logic_block_map) {
printk(KERN_WARNING
"SSFDC_RO: out of memory for data structures\n");
goto out_err;
}
memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) *
ssfdc->map_len);
/* Build logical block map */
if (build_logical_block_map(ssfdc) < 0)
goto out_err;
/* Register device + partitions */
if (add_mtd_blktrans_dev(&ssfdc->mbd))
goto out_err;
printk(KERN_INFO "SSFDC_RO: Found ssfdc%c on mtd%d (%s)\n",
ssfdc->mbd.devnum + 'a', mtd->index, mtd->name);
return;
out_err:
kfree(ssfdc->logic_block_map);
kfree(ssfdc);
}
static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev)
{
struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum);
del_mtd_blktrans_dev(dev);
kfree(ssfdc->logic_block_map);
kfree(ssfdc);
}
static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,
unsigned long logic_sect_no, char *buf)
{
struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
int sectors_per_block, offset, block_address;
sectors_per_block = ssfdc->erase_size >> SECTOR_SHIFT;
offset = (int)(logic_sect_no % sectors_per_block);
block_address = (int)(logic_sect_no / sectors_per_block);
DEBUG(MTD_DEBUG_LEVEL3,
"SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d,"
" block_addr=%d\n", logic_sect_no, sectors_per_block, offset,
block_address);
if (block_address >= ssfdc->map_len)
BUG();
block_address = ssfdc->logic_block_map[block_address];
DEBUG(MTD_DEBUG_LEVEL3,
"SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n",
block_address);
if (block_address < 0xffff) {
unsigned long sect_no;
sect_no = (unsigned long)block_address * sectors_per_block +
offset;
DEBUG(MTD_DEBUG_LEVEL3,
"SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n",
sect_no);
if (read_physical_sector( ssfdc->mbd.mtd, buf, sect_no ) < 0)
return -EIO;
} else {
memset(buf, 0xff, SECTOR_SIZE);
}
return 0;
}
static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
{
struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n",
ssfdc->cylinders, ssfdc->heads, ssfdc->sectors);
geo->heads = ssfdc->heads;
geo->sectors = ssfdc->sectors;
geo->cylinders = ssfdc->cylinders;
return 0;
}
/****************************************************************************
*
* Module stuff
*
****************************************************************************/
static struct mtd_blktrans_ops ssfdcr_tr = {
.name = "ssfdc",
.major = SSFDCR_MAJOR,
.part_bits = SSFDCR_PARTN_BITS,
.getgeo = ssfdcr_getgeo,
.readsect = ssfdcr_readsect,
.add_mtd = ssfdcr_add_mtd,
.remove_dev = ssfdcr_remove_dev,
.owner = THIS_MODULE,
};
static int __init init_ssfdcr(void)
{
printk(KERN_INFO "SSFDC read-only Flash Translation layer\n");
return register_mtd_blktrans(&ssfdcr_tr);
}
static void __exit cleanup_ssfdcr(void)
{
deregister_mtd_blktrans(&ssfdcr_tr);
}
module_init(init_ssfdcr);
module_exit(cleanup_ssfdcr);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>");
MODULE_DESCRIPTION("Flash Translation Layer for read-only SSFDC SmartMedia card");
......@@ -41,11 +41,7 @@ struct jffs2_inode_info {
uint16_t flags;
uint8_t usercompr;
#if !defined (__ECOS)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
struct inode vfs_inode;
#endif
#endif
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
struct posix_acl *i_acl_access;
struct posix_acl *i_acl_default;
......
......@@ -34,6 +34,7 @@ struct mtd_oob_buf {
#define MTD_WRITEABLE 0x400 /* Device is writeable */
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */
// Some common devices / combinations of capabilities
#define MTD_CAP_ROM 0
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册