mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-14 21:01:29 +00:00
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (46 commits) [MTD] [MAPS] drivers/mtd/maps/ck804xrom.c: convert pci_module_init() [MTD] [NAND] CM-x270 MTD driver [MTD] [NAND] Wrong calculation of page number in nand_block_bad() [MTD] [MAPS] fix plat-ram printk format [JFFS2] Fix compr_rubin.c build after include file elimination. [JFFS2] Handle inodes with only a single metadata node with non-zero isize [JFFS2] Tidy up licensing/copyright boilerplate. [MTD] [OneNAND] Exit loop only when column start with 0 [MTD] [OneNAND] Fix access the past of the real oobfree array [MTD] [OneNAND] Update Samsung OneNAND official URL [JFFS2] Better fix for all-zero node headers [JFFS2] Improve read_inode memory usage, v2. [JFFS2] Improve failure mode if inode checking leaves unchecked space. [JFFS2] Fix cross-endian build. [MTD] Finish conversion mtd_blkdevs to use the kthread API [JFFS2] Obsolete dirent nodes immediately on unlink, where possible. Use menuconfig objects: MTD [MTD] mtd_blkdevs: Convert to use the kthread API [MTD] Fix fwh_lock locking [JFFS2] Speed up mount for directly-mapped NOR flash ...
This commit is contained in:
commit
f00546363f
@ -1,8 +1,6 @@
|
||||
# $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $
|
||||
|
||||
menu "Memory Technology Devices (MTD)"
|
||||
|
||||
config MTD
|
||||
menuconfig MTD
|
||||
tristate "Memory Technology Device (MTD) support"
|
||||
help
|
||||
Memory Technology Devices are flash, RAM and similar chips, often
|
||||
@ -13,9 +11,10 @@ config MTD
|
||||
them. It will also allow you to select individual drivers for
|
||||
particular hardware and users of MTD devices. If unsure, say N.
|
||||
|
||||
if MTD
|
||||
|
||||
config MTD_DEBUG
|
||||
bool "Debugging"
|
||||
depends on MTD
|
||||
help
|
||||
This turns on low-level debugging for the entire MTD sub-system.
|
||||
Normally, you should say 'N'.
|
||||
@ -29,7 +28,6 @@ config MTD_DEBUG_VERBOSE
|
||||
|
||||
config MTD_CONCAT
|
||||
tristate "MTD concatenating support"
|
||||
depends on MTD
|
||||
help
|
||||
Support for concatenating several MTD devices into a single
|
||||
(virtual) one. This allows you to have -for example- a JFFS(2)
|
||||
@ -38,7 +36,6 @@ config MTD_CONCAT
|
||||
|
||||
config MTD_PARTITIONS
|
||||
bool "MTD partitioning support"
|
||||
depends on MTD
|
||||
help
|
||||
If you have a device which needs to divide its flash chip(s) up
|
||||
into multiple 'partitions', each of which appears to the user as
|
||||
@ -153,11 +150,9 @@ config MTD_AFS_PARTS
|
||||
'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
|
||||
|
||||
comment "User Modules And Translation Layers"
|
||||
depends on MTD
|
||||
|
||||
config MTD_CHAR
|
||||
tristate "Direct char device access to MTD devices"
|
||||
depends on MTD
|
||||
help
|
||||
This provides a character device for each MTD device present in
|
||||
the system, allowing the user to read and write directly to the
|
||||
@ -166,12 +161,12 @@ config MTD_CHAR
|
||||
|
||||
config MTD_BLKDEVS
|
||||
tristate "Common interface to block layer for MTD 'translation layers'"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
default n
|
||||
|
||||
config MTD_BLOCK
|
||||
tristate "Caching block device access to MTD devices"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
select MTD_BLKDEVS
|
||||
---help---
|
||||
Although most flash chips have an erase size too large to be useful
|
||||
@ -194,7 +189,7 @@ config MTD_BLOCK
|
||||
|
||||
config MTD_BLOCK_RO
|
||||
tristate "Readonly block device access to MTD devices"
|
||||
depends on MTD_BLOCK!=y && MTD && BLOCK
|
||||
depends on MTD_BLOCK!=y && BLOCK
|
||||
select MTD_BLKDEVS
|
||||
help
|
||||
This allows you to mount read-only file systems (such as cramfs)
|
||||
@ -206,7 +201,7 @@ config MTD_BLOCK_RO
|
||||
|
||||
config FTL
|
||||
tristate "FTL (Flash Translation Layer) support"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
select MTD_BLKDEVS
|
||||
---help---
|
||||
This provides support for the original Flash Translation Layer which
|
||||
@ -223,7 +218,7 @@ config FTL
|
||||
|
||||
config NFTL
|
||||
tristate "NFTL (NAND Flash Translation Layer) support"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
select MTD_BLKDEVS
|
||||
---help---
|
||||
This provides support for the NAND Flash Translation Layer which is
|
||||
@ -247,7 +242,7 @@ config NFTL_RW
|
||||
|
||||
config INFTL
|
||||
tristate "INFTL (Inverse NAND Flash Translation Layer) support"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
select MTD_BLKDEVS
|
||||
---help---
|
||||
This provides support for the Inverse NAND Flash Translation
|
||||
@ -265,7 +260,7 @@ config INFTL
|
||||
|
||||
config RFD_FTL
|
||||
tristate "Resident Flash Disk (Flash Translation Layer) support"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
select MTD_BLKDEVS
|
||||
---help---
|
||||
This provides support for the flash translation layer known
|
||||
@ -276,7 +271,7 @@ config RFD_FTL
|
||||
|
||||
config SSFDC
|
||||
tristate "NAND SSFDC (SmartMedia) read only translation layer"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
select MTD_BLKDEVS
|
||||
help
|
||||
This enables read only access to SmartMedia formatted NAND
|
||||
@ -294,5 +289,4 @@ source "drivers/mtd/onenand/Kconfig"
|
||||
|
||||
source "drivers/mtd/ubi/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
endif # MTD
|
||||
|
@ -6,7 +6,6 @@ menu "RAM/ROM/Flash chip drivers"
|
||||
|
||||
config MTD_CFI
|
||||
tristate "Detect flash chips by Common Flash Interface (CFI) probe"
|
||||
depends on MTD
|
||||
select MTD_GEN_PROBE
|
||||
help
|
||||
The Common Flash Interface specification was developed by Intel,
|
||||
@ -18,7 +17,6 @@ config MTD_CFI
|
||||
|
||||
config MTD_JEDECPROBE
|
||||
tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
|
||||
depends on MTD
|
||||
select MTD_GEN_PROBE
|
||||
help
|
||||
This option enables JEDEC-style probing of flash chips which are not
|
||||
@ -213,21 +211,18 @@ config MTD_CFI_UTIL
|
||||
|
||||
config MTD_RAM
|
||||
tristate "Support for RAM chips in bus mapping"
|
||||
depends on MTD
|
||||
help
|
||||
This option enables basic support for RAM chips accessed through
|
||||
a bus mapping driver.
|
||||
|
||||
config MTD_ROM
|
||||
tristate "Support for ROM chips in bus mapping"
|
||||
depends on MTD
|
||||
help
|
||||
This option enables basic support for ROM chips accessed through
|
||||
a bus mapping driver.
|
||||
|
||||
config MTD_ABSENT
|
||||
tristate "Support for absent chips in bus mapping"
|
||||
depends on MTD
|
||||
help
|
||||
This option enables support for a dummy probing driver used to
|
||||
allocated placeholder MTD devices on systems that have socketed
|
||||
@ -237,7 +232,6 @@ config MTD_ABSENT
|
||||
with this driver will return -ENODEV upon access.
|
||||
|
||||
config MTD_OBSOLETE_CHIPS
|
||||
depends on MTD
|
||||
bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
|
||||
help
|
||||
This option does not enable any code directly, but will allow you to
|
||||
@ -250,7 +244,7 @@ config MTD_OBSOLETE_CHIPS
|
||||
|
||||
config MTD_AMDSTD
|
||||
tristate "AMD compatible flash chip support (non-CFI)"
|
||||
depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
|
||||
depends on MTD_OBSOLETE_CHIPS && BROKEN
|
||||
help
|
||||
This option enables support for flash chips using AMD-compatible
|
||||
commands, including some which are not CFI-compatible and hence
|
||||
@ -260,7 +254,7 @@ config MTD_AMDSTD
|
||||
|
||||
config MTD_SHARP
|
||||
tristate "pre-CFI Sharp chip support"
|
||||
depends on MTD && MTD_OBSOLETE_CHIPS
|
||||
depends on MTD_OBSOLETE_CHIPS
|
||||
help
|
||||
This option enables support for flash chips using Sharp-compatible
|
||||
commands, including some which are not CFI-compatible and hence
|
||||
@ -268,7 +262,7 @@ config MTD_SHARP
|
||||
|
||||
config MTD_JEDEC
|
||||
tristate "JEDEC device support"
|
||||
depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
|
||||
depends on MTD_OBSOLETE_CHIPS && BROKEN
|
||||
help
|
||||
Enable older JEDEC flash interface devices for self
|
||||
programming flash. It is commonly used in older AMD chips. It is
|
||||
|
@ -15,6 +15,8 @@
|
||||
* - optimized write buffer method
|
||||
* 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
|
||||
* - reworked lock/unlock/erase support for var size flash
|
||||
* 21/03/2007 Rodolfo Giometti <giometti@linux.it>
|
||||
* - auto unlock sectors on resume for auto locking flash on power up
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -30,6 +32,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/mtd/xip.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
@ -220,6 +223,15 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some chips power-up with all sectors locked by default.
|
||||
*/
|
||||
static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
|
||||
{
|
||||
printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
|
||||
mtd->flags |= MTD_STUPID_LOCK;
|
||||
}
|
||||
|
||||
static struct cfi_fixup cfi_fixup_table[] = {
|
||||
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
|
||||
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
|
||||
@ -232,6 +244,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
|
||||
#endif
|
||||
{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
|
||||
{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
|
||||
{ MANUFACTURER_INTEL, 0x891c, fixup_use_powerup_lock, NULL, },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
@ -460,6 +473,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
|
||||
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
|
||||
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
|
||||
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
|
||||
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL);
|
||||
}
|
||||
offset += (ersize * ernum);
|
||||
}
|
||||
@ -1825,8 +1839,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOCK_BITS
|
||||
static int __xipram do_printlockstatus_oneblock(struct map_info *map,
|
||||
static int __xipram do_getlockstatus_oneblock(struct map_info *map,
|
||||
struct flchip *chip,
|
||||
unsigned long adr,
|
||||
int len, void *thunk)
|
||||
@ -1840,8 +1853,17 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
|
||||
chip->state = FL_JEDEC_QUERY;
|
||||
status = cfi_read_query(map, adr+(2*ofs_factor));
|
||||
xip_enable(map, chip, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOCK_BITS
|
||||
static int __xipram do_printlockstatus_oneblock(struct map_info *map,
|
||||
struct flchip *chip,
|
||||
unsigned long adr,
|
||||
int len, void *thunk)
|
||||
{
|
||||
printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
|
||||
adr, status);
|
||||
adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -2216,14 +2238,45 @@ static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
|
||||
|
||||
#endif
|
||||
|
||||
static void cfi_intelext_save_locks(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_erase_region_info *region;
|
||||
int block, status, i;
|
||||
unsigned long adr;
|
||||
size_t len;
|
||||
|
||||
for (i = 0; i < mtd->numeraseregions; i++) {
|
||||
region = &mtd->eraseregions[i];
|
||||
if (!region->lockmap)
|
||||
continue;
|
||||
|
||||
for (block = 0; block < region->numblocks; block++){
|
||||
len = region->erasesize;
|
||||
adr = region->offset + block * len;
|
||||
|
||||
status = cfi_varsize_frob(mtd,
|
||||
do_getlockstatus_oneblock, adr, len, 0);
|
||||
if (status)
|
||||
set_bit(block, region->lockmap);
|
||||
else
|
||||
clear_bit(block, region->lockmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cfi_intelext_suspend(struct mtd_info *mtd)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
|
||||
int i;
|
||||
struct flchip *chip;
|
||||
int ret = 0;
|
||||
|
||||
if ((mtd->flags & MTD_STUPID_LOCK)
|
||||
&& extp && (extp->FeatureSupport & (1 << 5)))
|
||||
cfi_intelext_save_locks(mtd);
|
||||
|
||||
for (i=0; !ret && i<cfi->numchips; i++) {
|
||||
chip = &cfi->chips[i];
|
||||
|
||||
@ -2285,10 +2338,33 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cfi_intelext_restore_locks(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_erase_region_info *region;
|
||||
int block, i;
|
||||
unsigned long adr;
|
||||
size_t len;
|
||||
|
||||
for (i = 0; i < mtd->numeraseregions; i++) {
|
||||
region = &mtd->eraseregions[i];
|
||||
if (!region->lockmap)
|
||||
continue;
|
||||
|
||||
for (block = 0; block < region->numblocks; block++) {
|
||||
len = region->erasesize;
|
||||
adr = region->offset + block * len;
|
||||
|
||||
if (!test_bit(block, region->lockmap))
|
||||
cfi_intelext_unlock(mtd, adr, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cfi_intelext_resume(struct mtd_info *mtd)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
|
||||
int i;
|
||||
struct flchip *chip;
|
||||
|
||||
@ -2307,6 +2383,10 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
|
||||
|
||||
spin_unlock(chip->mutex);
|
||||
}
|
||||
|
||||
if ((mtd->flags & MTD_STUPID_LOCK)
|
||||
&& extp && (extp->FeatureSupport & (1 << 5)))
|
||||
cfi_intelext_restore_locks(mtd);
|
||||
}
|
||||
|
||||
static int cfi_intelext_reset(struct mtd_info *mtd)
|
||||
@ -2347,12 +2427,19 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
struct mtd_erase_region_info *region;
|
||||
int i;
|
||||
cfi_intelext_reset(mtd);
|
||||
unregister_reboot_notifier(&mtd->reboot_notifier);
|
||||
kfree(cfi->cmdset_priv);
|
||||
kfree(cfi->cfiq);
|
||||
kfree(cfi->chips[0].priv);
|
||||
kfree(cfi);
|
||||
for (i = 0; i < mtd->numeraseregions; i++) {
|
||||
region = &mtd->eraseregions[i];
|
||||
if (region->lockmap)
|
||||
kfree(region->lockmap);
|
||||
}
|
||||
kfree(mtd->eraseregions);
|
||||
}
|
||||
|
||||
|
@ -65,11 +65,12 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip->oldstate = chip->state;
|
||||
chip->state = xxlt->state;
|
||||
map_write(map, CMD(xxlt->val), adr);
|
||||
|
||||
/* Done and happy. */
|
||||
chip->state = FL_READY;
|
||||
chip->state = chip->oldstate;
|
||||
put_chip(map, chip, adr);
|
||||
spin_unlock(chip->mutex);
|
||||
return 0;
|
||||
|
@ -6,7 +6,7 @@ menu "Self-contained MTD device drivers"
|
||||
|
||||
config MTD_PMC551
|
||||
tristate "Ramix PMC551 PCI Mezzanine RAM card support"
|
||||
depends on MTD && PCI
|
||||
depends on PCI
|
||||
---help---
|
||||
This provides a MTD device driver for the Ramix PMC551 RAM PCI card
|
||||
from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
|
||||
@ -40,7 +40,7 @@ config MTD_PMC551_DEBUG
|
||||
|
||||
config MTD_MS02NV
|
||||
tristate "DEC MS02-NV NVRAM module support"
|
||||
depends on MTD && MACH_DECSTATION
|
||||
depends on MACH_DECSTATION
|
||||
help
|
||||
This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery
|
||||
backed-up NVRAM module. The module was originally meant as an NFS
|
||||
@ -54,15 +54,23 @@ config MTD_MS02NV
|
||||
|
||||
config MTD_DATAFLASH
|
||||
tristate "Support for AT45xxx DataFlash"
|
||||
depends on MTD && SPI_MASTER && EXPERIMENTAL
|
||||
depends on SPI_MASTER && EXPERIMENTAL
|
||||
help
|
||||
This enables access to AT45xxx DataFlash chips, using SPI.
|
||||
Sometimes DataFlash chips are packaged inside MMC-format
|
||||
cards; at this writing, the MMC stack won't handle those.
|
||||
|
||||
config MTD_DATAFLASH26
|
||||
tristate "AT91RM9200 DataFlash AT26xxx"
|
||||
depends on MTD && ARCH_AT91RM9200 && AT91_SPI
|
||||
help
|
||||
This enables access to the DataFlash chip (AT26xxx) on an
|
||||
AT91RM9200-based board.
|
||||
If you have such a board and such a DataFlash, say 'Y'.
|
||||
|
||||
config MTD_M25P80
|
||||
tristate "Support for M25 SPI Flash"
|
||||
depends on MTD && SPI_MASTER && EXPERIMENTAL
|
||||
depends on SPI_MASTER && EXPERIMENTAL
|
||||
help
|
||||
This enables access to ST M25P80 and similar SPI flash chips,
|
||||
used for program and data storage. Set up your spi devices
|
||||
@ -70,7 +78,6 @@ config MTD_M25P80
|
||||
|
||||
config MTD_SLRAM
|
||||
tristate "Uncached system RAM"
|
||||
depends on MTD
|
||||
help
|
||||
If your CPU cannot cache all of the physical memory in your machine,
|
||||
you can still use it for storage or swap by using this driver to
|
||||
@ -78,7 +85,6 @@ config MTD_SLRAM
|
||||
|
||||
config MTD_PHRAM
|
||||
tristate "Physical system RAM"
|
||||
depends on MTD
|
||||
help
|
||||
This is a re-implementation of the slram driver above.
|
||||
|
||||
@ -88,7 +94,7 @@ config MTD_PHRAM
|
||||
|
||||
config MTD_LART
|
||||
tristate "28F160xx flash driver for LART"
|
||||
depends on SA1100_LART && MTD
|
||||
depends on SA1100_LART
|
||||
help
|
||||
This enables the flash driver for LART. Please note that you do
|
||||
not need any mapping/chip driver for LART. This one does it all
|
||||
@ -96,7 +102,6 @@ config MTD_LART
|
||||
|
||||
config MTD_MTDRAM
|
||||
tristate "Test driver using RAM"
|
||||
depends on MTD
|
||||
help
|
||||
This enables a test MTD device driver which uses vmalloc() to
|
||||
provide storage. You probably want to say 'N' unless you're
|
||||
@ -136,7 +141,7 @@ config MTDRAM_ABS_POS
|
||||
|
||||
config MTD_BLOCK2MTD
|
||||
tristate "MTD using block device"
|
||||
depends on MTD && BLOCK
|
||||
depends on BLOCK
|
||||
help
|
||||
This driver allows a block device to appear as an MTD. It would
|
||||
generally be used in the following cases:
|
||||
@ -150,7 +155,6 @@ comment "Disk-On-Chip Device Drivers"
|
||||
|
||||
config MTD_DOC2000
|
||||
tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
|
||||
depends on MTD
|
||||
select MTD_DOCPROBE
|
||||
select MTD_NAND_IDS
|
||||
---help---
|
||||
@ -173,7 +177,6 @@ config MTD_DOC2000
|
||||
|
||||
config MTD_DOC2001
|
||||
tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
|
||||
depends on MTD
|
||||
select MTD_DOCPROBE
|
||||
select MTD_NAND_IDS
|
||||
---help---
|
||||
@ -195,7 +198,6 @@ config MTD_DOC2001
|
||||
|
||||
config MTD_DOC2001PLUS
|
||||
tristate "M-Systems Disk-On-Chip Millennium Plus"
|
||||
depends on MTD
|
||||
select MTD_DOCPROBE
|
||||
select MTD_NAND_IDS
|
||||
---help---
|
||||
|
@ -16,4 +16,5 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
|
||||
obj-$(CONFIG_MTD_LART) += lart.o
|
||||
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
||||
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
||||
obj-$(CONFIG_MTD_DATAFLASH26) += at91_dataflash26.o
|
||||
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
||||
|
485
drivers/mtd/devices/at91_dataflash26.c
Normal file
485
drivers/mtd/devices/at91_dataflash26.c
Normal file
@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
|
||||
* This is a largely modified version of at91_dataflash.c that
|
||||
* supports AT26xxx dataflash chips. The original driver supports
|
||||
* AT45xxx chips.
|
||||
*
|
||||
* Note: This driver was only tested with an AT26F004. It should be
|
||||
* easy to make it work with other AT26xxx dataflash devices, though.
|
||||
*
|
||||
* Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
|
||||
* original Copyright (C) SAN People (Pty) Ltd
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
|
||||
#include <asm/arch/at91_spi.h>
|
||||
|
||||
#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */
|
||||
|
||||
#define MANUFACTURER_ID_ATMEL 0x1F
|
||||
|
||||
/* command codes */
|
||||
|
||||
#define AT26_OP_READ_STATUS 0x05
|
||||
#define AT26_OP_READ_DEV_ID 0x9F
|
||||
#define AT26_OP_ERASE_PAGE_4K 0x20
|
||||
#define AT26_OP_READ_ARRAY_FAST 0x0B
|
||||
#define AT26_OP_SEQUENTIAL_WRITE 0xAF
|
||||
#define AT26_OP_WRITE_ENABLE 0x06
|
||||
#define AT26_OP_WRITE_DISABLE 0x04
|
||||
#define AT26_OP_SECTOR_PROTECT 0x36
|
||||
#define AT26_OP_SECTOR_UNPROTECT 0x39
|
||||
|
||||
/* status register bits */
|
||||
|
||||
#define AT26_STATUS_BUSY 0x01
|
||||
#define AT26_STATUS_WRITE_ENABLE 0x02
|
||||
|
||||
struct dataflash_local
|
||||
{
|
||||
int spi; /* SPI chip-select number */
|
||||
unsigned int page_size; /* number of bytes per page */
|
||||
};
|
||||
|
||||
|
||||
/* Detected DataFlash devices */
|
||||
static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
|
||||
static int nr_devices = 0;
|
||||
|
||||
/* Allocate a single SPI transfer descriptor. We're assuming that if multiple
|
||||
SPI transfers occur at the same time, spi_access_bus() will serialize them.
|
||||
If this is not valid, then either (i) each dataflash 'priv' structure
|
||||
needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
|
||||
another mechanism. */
|
||||
static struct spi_transfer_list* spi_transfer_desc;
|
||||
|
||||
/*
|
||||
* Perform a SPI transfer to access the DataFlash device.
|
||||
*/
|
||||
static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
|
||||
char* txnext, int txnext_len, char* rxnext, int rxnext_len)
|
||||
{
|
||||
struct spi_transfer_list* list = spi_transfer_desc;
|
||||
|
||||
list->tx[0] = tx; list->txlen[0] = tx_len;
|
||||
list->rx[0] = rx; list->rxlen[0] = rx_len;
|
||||
|
||||
list->tx[1] = txnext; list->txlen[1] = txnext_len;
|
||||
list->rx[1] = rxnext; list->rxlen[1] = rxnext_len;
|
||||
|
||||
list->nr_transfers = nr;
|
||||
/* Note: spi_transfer() always returns 0, there are no error checks */
|
||||
return spi_transfer(list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the status of the DataFlash device.
|
||||
*/
|
||||
static unsigned char at91_dataflash26_status(void)
|
||||
{
|
||||
unsigned char command[2];
|
||||
|
||||
command[0] = AT26_OP_READ_STATUS;
|
||||
command[1] = 0;
|
||||
|
||||
do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
|
||||
|
||||
return command[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll the DataFlash device until it is READY.
|
||||
*/
|
||||
static unsigned char at91_dataflash26_waitready(void)
|
||||
{
|
||||
unsigned char status;
|
||||
|
||||
while (1) {
|
||||
status = at91_dataflash26_status();
|
||||
if (!(status & AT26_STATUS_BUSY))
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable/disable write access
|
||||
*/
|
||||
static void at91_dataflash26_write_enable(int enable)
|
||||
{
|
||||
unsigned char cmd[2];
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable);
|
||||
|
||||
if (enable)
|
||||
cmd[0] = AT26_OP_WRITE_ENABLE;
|
||||
else
|
||||
cmd[0] = AT26_OP_WRITE_DISABLE;
|
||||
cmd[1] = 0;
|
||||
|
||||
do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Protect/unprotect sector
|
||||
*/
|
||||
static void at91_dataflash26_sector_protect(loff_t addr, int protect)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n",
|
||||
addr, protect);
|
||||
|
||||
if (protect)
|
||||
cmd[0] = AT26_OP_SECTOR_PROTECT;
|
||||
else
|
||||
cmd[0] = AT26_OP_SECTOR_UNPROTECT;
|
||||
cmd[1] = (addr & 0x00FF0000) >> 16;
|
||||
cmd[2] = (addr & 0x0000FF00) >> 8;
|
||||
cmd[3] = (addr & 0x000000FF);
|
||||
|
||||
do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase blocks of flash.
|
||||
*/
|
||||
static int at91_dataflash26_erase(struct mtd_info *mtd,
|
||||
struct erase_info *instr)
|
||||
{
|
||||
struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
|
||||
unsigned char cmd[4];
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n",
|
||||
instr->addr, instr->len);
|
||||
|
||||
/* Sanity checks */
|
||||
if (priv->page_size != 4096)
|
||||
return -EINVAL; /* Can't handle other sizes at the moment */
|
||||
|
||||
if ( ((instr->len % mtd->erasesize) != 0)
|
||||
|| ((instr->len % priv->page_size) != 0)
|
||||
|| ((instr->addr % priv->page_size) != 0)
|
||||
|| ((instr->addr + instr->len) > mtd->size))
|
||||
return -EINVAL;
|
||||
|
||||
spi_access_bus(priv->spi);
|
||||
|
||||
while (instr->len > 0) {
|
||||
at91_dataflash26_write_enable(1);
|
||||
at91_dataflash26_sector_protect(instr->addr, 0);
|
||||
at91_dataflash26_write_enable(1);
|
||||
cmd[0] = AT26_OP_ERASE_PAGE_4K;
|
||||
cmd[1] = (instr->addr & 0x00FF0000) >> 16;
|
||||
cmd[2] = (instr->addr & 0x0000FF00) >> 8;
|
||||
cmd[3] = (instr->addr & 0x000000FF);
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x"
|
||||
"0x%02x\n",
|
||||
cmd[0], cmd[1], cmd[2], cmd[3]);
|
||||
|
||||
do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
|
||||
at91_dataflash26_waitready();
|
||||
|
||||
instr->addr += priv->page_size; /* next page */
|
||||
instr->len -= priv->page_size;
|
||||
}
|
||||
|
||||
at91_dataflash26_write_enable(0);
|
||||
spi_release_bus(priv->spi);
|
||||
|
||||
/* Inform MTD subsystem that erase is complete */
|
||||
instr->state = MTD_ERASE_DONE;
|
||||
if (instr->callback)
|
||||
instr->callback(instr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the DataFlash device.
|
||||
* from : Start offset in flash device
|
||||
* len : Number of bytes to read
|
||||
* retlen : Number of bytes actually read
|
||||
* buf : Buffer that will receive data
|
||||
*/
|
||||
static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
|
||||
unsigned char cmd[5];
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n",
|
||||
from, from+len);
|
||||
|
||||
*retlen = 0;
|
||||
|
||||
/* Sanity checks */
|
||||
if (!len)
|
||||
return 0;
|
||||
if (from + len > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
cmd[0] = AT26_OP_READ_ARRAY_FAST;
|
||||
cmd[1] = (from & 0x00FF0000) >> 16;
|
||||
cmd[2] = (from & 0x0000FF00) >> 8;
|
||||
cmd[3] = (from & 0x000000FF);
|
||||
/* cmd[4] is a "Don't care" byte */
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n",
|
||||
cmd[0], cmd[1], cmd[2], cmd[3]);
|
||||
|
||||
spi_access_bus(priv->spi);
|
||||
do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len);
|
||||
spi_release_bus(priv->spi);
|
||||
|
||||
*retlen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to the DataFlash device.
|
||||
* to : Start offset in flash device
|
||||
* len : Number of bytes to write
|
||||
* retlen : Number of bytes actually written
|
||||
* buf : Buffer containing the data
|
||||
*/
|
||||
static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
|
||||
unsigned int addr, buf_index = 0;
|
||||
int ret = -EIO, sector, last_sector;
|
||||
unsigned char status, cmd[5];
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len);
|
||||
|
||||
*retlen = 0;
|
||||
|
||||
/* Sanity checks */
|
||||
if (!len)
|
||||
return 0;
|
||||
if (to + len > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
spi_access_bus(priv->spi);
|
||||
|
||||
addr = to;
|
||||
last_sector = -1;
|
||||
|
||||
while (buf_index < len) {
|
||||
sector = addr / priv->page_size;
|
||||
/* Write first byte if a new sector begins */
|
||||
if (sector != last_sector) {
|
||||
at91_dataflash26_write_enable(1);
|
||||
at91_dataflash26_sector_protect(addr, 0);
|
||||
at91_dataflash26_write_enable(1);
|
||||
|
||||
/* Program first byte of a new sector */
|
||||
cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
|
||||
cmd[1] = (addr & 0x00FF0000) >> 16;
|
||||
cmd[2] = (addr & 0x0000FF00) >> 8;
|
||||
cmd[3] = (addr & 0x000000FF);
|
||||
cmd[4] = buf[buf_index++];
|
||||
do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
|
||||
status = at91_dataflash26_waitready();
|
||||
addr++;
|
||||
/* On write errors, the chip resets the write enable
|
||||
flag. This also happens after the last byte of a
|
||||
sector is successfully programmed. */
|
||||
if ( ( !(status & AT26_STATUS_WRITE_ENABLE))
|
||||
&& ((addr % priv->page_size) != 0) ) {
|
||||
DEBUG(MTD_DEBUG_LEVEL1,
|
||||
"write error1: addr=0x%06x, "
|
||||
"status=0x%02x\n", addr, status);
|
||||
goto write_err;
|
||||
}
|
||||
(*retlen)++;
|
||||
last_sector = sector;
|
||||
}
|
||||
|
||||
/* Write subsequent bytes in the same sector */
|
||||
cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
|
||||
cmd[1] = buf[buf_index++];
|
||||
do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
|
||||
status = at91_dataflash26_waitready();
|
||||
addr++;
|
||||
|
||||
if ( ( !(status & AT26_STATUS_WRITE_ENABLE))
|
||||
&& ((addr % priv->page_size) != 0) ) {
|
||||
DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, "
|
||||
"status=0x%02x\n", addr, status);
|
||||
goto write_err;
|
||||
}
|
||||
|
||||
(*retlen)++;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
at91_dataflash26_write_enable(0);
|
||||
write_err:
|
||||
spi_release_bus(priv->spi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize and register DataFlash device with MTD subsystem.
|
||||
*/
|
||||
static int __init add_dataflash(int channel, char *name, int nr_pages,
|
||||
int pagesize)
|
||||
{
|
||||
struct mtd_info *device;
|
||||
struct dataflash_local *priv;
|
||||
|
||||
if (nr_devices >= DATAFLASH_MAX_DEVICES) {
|
||||
printk(KERN_ERR "at91_dataflash26: Too many devices "
|
||||
"detected\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8,
|
||||
GFP_KERNEL);
|
||||
if (!device)
|
||||
return -ENOMEM;
|
||||
|
||||
device->name = (char *)&device[1];
|
||||
sprintf(device->name, "%s.spi%d", name, channel);
|
||||
device->size = nr_pages * pagesize;
|
||||
device->erasesize = pagesize;
|
||||
device->owner = THIS_MODULE;
|
||||
device->type = MTD_DATAFLASH;
|
||||
device->flags = MTD_CAP_NORFLASH;
|
||||
device->erase = at91_dataflash26_erase;
|
||||
device->read = at91_dataflash26_read;
|
||||
device->write = at91_dataflash26_write;
|
||||
|
||||
priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local),
|
||||
GFP_KERNEL);
|
||||
if (!priv) {
|
||||
kfree(device);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->spi = channel;
|
||||
priv->page_size = pagesize;
|
||||
device->priv = priv;
|
||||
|
||||
mtd_devices[nr_devices] = device;
|
||||
nr_devices++;
|
||||
printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n",
|
||||
name, channel, device->size);
|
||||
|
||||
return add_mtd_device(device);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect and initialize DataFlash device connected to specified SPI channel.
|
||||
*
|
||||
*/
|
||||
|
||||
struct dataflash26_types {
|
||||
unsigned char id0;
|
||||
unsigned char id1;
|
||||
char *name;
|
||||
int pagesize;
|
||||
int nr_pages;
|
||||
};
|
||||
|
||||
struct dataflash26_types df26_types[] = {
|
||||
{
|
||||
.id0 = 0x04,
|
||||
.id1 = 0x00,
|
||||
.name = "AT26F004",
|
||||
.pagesize = 4096,
|
||||
.nr_pages = 128,
|
||||
},
|
||||
{
|
||||
.id0 = 0x45,
|
||||
.id1 = 0x01,
|
||||
.name = "AT26DF081A", /* Not tested ! */
|
||||
.pagesize = 4096,
|
||||
.nr_pages = 256,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init at91_dataflash26_detect(int channel)
|
||||
{
|
||||
unsigned char status, cmd[5];
|
||||
int i;
|
||||
|
||||
spi_access_bus(channel);
|
||||
status = at91_dataflash26_status();
|
||||
|
||||
if (status == 0 || status == 0xff) {
|
||||
printk(KERN_ERR "at91_dataflash26_detect: status error %d\n",
|
||||
status);
|
||||
spi_release_bus(channel);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cmd[0] = AT26_OP_READ_DEV_ID;
|
||||
do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
|
||||
spi_release_bus(channel);
|
||||
|
||||
if (cmd[1] != MANUFACTURER_ID_ATMEL)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(df26_types); i++) {
|
||||
if ( cmd[2] == df26_types[i].id0
|
||||
&& cmd[3] == df26_types[i].id1)
|
||||
return add_dataflash(channel,
|
||||
df26_types[i].name,
|
||||
df26_types[i].nr_pages,
|
||||
df26_types[i].pagesize);
|
||||
}
|
||||
|
||||
printk(KERN_ERR "at91_dataflash26_detect: Unsupported device "
|
||||
"(0x%02x/0x%02x)\n", cmd[2], cmd[3]);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int __init at91_dataflash26_init(void)
|
||||
{
|
||||
spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list),
|
||||
GFP_KERNEL);
|
||||
if (!spi_transfer_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
/* DataFlash (SPI chip select 0) */
|
||||
at91_dataflash26_detect(0);
|
||||
|
||||
#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
|
||||
/* DataFlash card (SPI chip select 3) */
|
||||
at91_dataflash26_detect(3);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit at91_dataflash26_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
|
||||
if (mtd_devices[i]) {
|
||||
del_mtd_device(mtd_devices[i]);
|
||||
kfree(mtd_devices[i]->priv);
|
||||
kfree(mtd_devices[i]);
|
||||
}
|
||||
}
|
||||
nr_devices = 0;
|
||||
kfree(spi_transfer_desc);
|
||||
}
|
||||
|
||||
module_init(at91_dataflash26_init);
|
||||
module_exit(at91_dataflash26_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Hans J. Koch");
|
||||
MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200");
|
@ -40,56 +40,9 @@ struct block2mtd_dev {
|
||||
static LIST_HEAD(blkmtd_device_list);
|
||||
|
||||
|
||||
#define PAGE_READAHEAD 64
|
||||
static void cache_readahead(struct address_space *mapping, int index)
|
||||
static struct page* page_read(struct address_space *mapping, int index)
|
||||
{
|
||||
filler_t *filler = (filler_t*)mapping->a_ops->readpage;
|
||||
int i, pagei;
|
||||
unsigned ret = 0;
|
||||
unsigned long end_index;
|
||||
struct page *page;
|
||||
LIST_HEAD(page_pool);
|
||||
struct inode *inode = mapping->host;
|
||||
loff_t isize = i_size_read(inode);
|
||||
|
||||
if (!isize) {
|
||||
INFO("iSize=0 in cache_readahead\n");
|
||||
return;
|
||||
}
|
||||
|
||||
end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
|
||||
|
||||
read_lock_irq(&mapping->tree_lock);
|
||||
for (i = 0; i < PAGE_READAHEAD; i++) {
|
||||
pagei = index + i;
|
||||
if (pagei > end_index) {
|
||||
INFO("Overrun end of disk in cache readahead\n");
|
||||
break;
|
||||
}
|
||||
page = radix_tree_lookup(&mapping->page_tree, pagei);
|
||||
if (page && (!i))
|
||||
break;
|
||||
if (page)
|
||||
continue;
|
||||
read_unlock_irq(&mapping->tree_lock);
|
||||
page = page_cache_alloc_cold(mapping);
|
||||
read_lock_irq(&mapping->tree_lock);
|
||||
if (!page)
|
||||
break;
|
||||
page->index = pagei;
|
||||
list_add(&page->lru, &page_pool);
|
||||
ret++;
|
||||
}
|
||||
read_unlock_irq(&mapping->tree_lock);
|
||||
if (ret)
|
||||
read_cache_pages(mapping, &page_pool, filler, NULL);
|
||||
}
|
||||
|
||||
|
||||
static struct page* page_readahead(struct address_space *mapping, int index)
|
||||
{
|
||||
filler_t *filler = (filler_t*)mapping->a_ops->readpage;
|
||||
cache_readahead(mapping, index);
|
||||
return read_cache_page(mapping, index, filler, NULL);
|
||||
}
|
||||
|
||||
@ -105,14 +58,14 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
|
||||
u_long *max;
|
||||
|
||||
while (pages) {
|
||||
page = page_readahead(mapping, index);
|
||||
page = page_read(mapping, index);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
|
||||
max = (u_long*)page_address(page) + PAGE_SIZE;
|
||||
for (p=(u_long*)page_address(page); p<max; p++)
|
||||
max = page_address(page) + PAGE_SIZE;
|
||||
for (p=page_address(page); p<max; p++)
|
||||
if (*p != -1UL) {
|
||||
lock_page(page);
|
||||
memset(page_address(page), 0xff, PAGE_SIZE);
|
||||
@ -174,8 +127,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
cpylen = len; // this page
|
||||
len = len - cpylen;
|
||||
|
||||
// Get page
|
||||
page = page_readahead(dev->blkdev->bd_inode->i_mapping, index);
|
||||
page = page_read(dev->blkdev->bd_inode->i_mapping, index);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
if (IS_ERR(page))
|
||||
@ -213,8 +165,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
|
||||
cpylen = len; // this page
|
||||
len = len - cpylen;
|
||||
|
||||
// Get page
|
||||
page = page_readahead(mapping, index);
|
||||
page = page_read(mapping, index);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
if (IS_ERR(page))
|
||||
@ -308,9 +259,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
|
||||
/* We might not have rootfs mounted at this point. Try
|
||||
to resolve the device name by other means. */
|
||||
|
||||
dev_t dev = name_to_dev_t(devname);
|
||||
if (dev != 0) {
|
||||
bdev = open_by_devnum(dev, FMODE_WRITE | FMODE_READ);
|
||||
dev_t devt = name_to_dev_t(devname);
|
||||
if (devt) {
|
||||
bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -6,7 +6,6 @@ menu "Mapping drivers for chip access"
|
||||
|
||||
config MTD_COMPLEX_MAPPINGS
|
||||
bool "Support non-linear mappings of flash chips"
|
||||
depends on MTD
|
||||
help
|
||||
This causes the chip drivers to allow for complicated
|
||||
paged mappings of flash chips.
|
||||
@ -69,6 +68,39 @@ config MTD_PHYSMAP_OF
|
||||
physically into the CPU's memory. The mapping description here is
|
||||
taken from OF device tree.
|
||||
|
||||
config MTD_PMC_MSP_EVM
|
||||
tristate "CFI Flash device mapped on PMC-Sierra MSP"
|
||||
depends on PMC_MSP && MTD_CFI
|
||||
select MTD_PARTITIONS
|
||||
help
|
||||
This provides a 'mapping' driver which support the way
|
||||
in which user-programmable flash chips are connected on the
|
||||
PMC-Sierra MSP eval/demo boards
|
||||
|
||||
choice
|
||||
prompt "Maximum mappable memory avialable for flash IO"
|
||||
depends on MTD_PMC_MSP_EVM
|
||||
default MSP_FLASH_MAP_LIMIT_32M
|
||||
|
||||
config MSP_FLASH_MAP_LIMIT_32M
|
||||
bool "32M"
|
||||
|
||||
endchoice
|
||||
|
||||
config MSP_FLASH_MAP_LIMIT
|
||||
hex
|
||||
default "0x02000000"
|
||||
depends on MSP_FLASH_MAP_LIMIT_32M
|
||||
|
||||
config MTD_PMC_MSP_RAMROOT
|
||||
tristate "Embedded RAM block device for root on PMC-Sierra MSP"
|
||||
depends on PMC_MSP_EMBEDDED_ROOTFS && \
|
||||
(MTD_BLOCK || MTD_BLOCK_RO) && \
|
||||
MTD_RAM
|
||||
help
|
||||
This provides support for the embedded root file system
|
||||
on PMC MSP devices. This memory is mapped as a MTD block device.
|
||||
|
||||
config MTD_SUN_UFLASH
|
||||
tristate "Sun Microsystems userflash support"
|
||||
depends on SPARC && MTD_CFI
|
||||
@ -240,13 +272,13 @@ config MTD_NETtel
|
||||
|
||||
config MTD_ALCHEMY
|
||||
tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support"
|
||||
depends on SOC_AU1X00
|
||||
depends on SOC_AU1X00 && MTD_PARTITIONS && MTD_CFI
|
||||
help
|
||||
Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
|
||||
|
||||
config MTD_MTX1
|
||||
tristate "4G Systems MTX-1 Flash device"
|
||||
depends on MIPS && MIPS_MTX1
|
||||
depends on MIPS_MTX1 && MTD_CFI
|
||||
help
|
||||
Flash memory access on 4G Systems MTX-1 Board. If you have one of
|
||||
these boards and would like to use the flash chips on it, say 'Y'.
|
||||
@ -384,7 +416,7 @@ config MTD_TQM834x
|
||||
|
||||
config MTD_OCELOT
|
||||
tristate "Momenco Ocelot boot flash device"
|
||||
depends on MIPS && MOMENCO_OCELOT
|
||||
depends on MOMENCO_OCELOT
|
||||
help
|
||||
This enables access routines for the boot flash device and for the
|
||||
NVRAM on the Momenco Ocelot board. If you have one of these boards
|
||||
@ -517,7 +549,7 @@ config MTD_OMAP_NOR
|
||||
# This needs CFI or JEDEC, depending on the cards found.
|
||||
config MTD_PCI
|
||||
tristate "PCI MTD driver"
|
||||
depends on MTD && PCI && MTD_COMPLEX_MAPPINGS
|
||||
depends on PCI && MTD_COMPLEX_MAPPINGS
|
||||
help
|
||||
Mapping for accessing flash devices on add-in cards like the Intel XScale
|
||||
IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode
|
||||
@ -527,7 +559,7 @@ config MTD_PCI
|
||||
|
||||
config MTD_PCMCIA
|
||||
tristate "PCMCIA MTD driver"
|
||||
depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN
|
||||
depends on PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN
|
||||
help
|
||||
Map driver for accessing PCMCIA linear flash memory cards. These
|
||||
cards are usually around 4-16MiB in size. This does not include
|
||||
@ -591,13 +623,12 @@ config MTD_BAST_MAXSIZE
|
||||
|
||||
config MTD_SHARP_SL
|
||||
bool "ROM mapped on Sharp SL Series"
|
||||
depends on MTD && ARCH_PXA
|
||||
depends on ARCH_PXA
|
||||
help
|
||||
This enables access to the flash chip on the Sharp SL Series of PDAs.
|
||||
|
||||
config MTD_PLATRAM
|
||||
tristate "Map driver for platform device RAM (mtd-ram)"
|
||||
depends on MTD
|
||||
select MTD_RAM
|
||||
help
|
||||
Map driver for RAM areas described via the platform device
|
||||
|
@ -27,6 +27,8 @@ obj-$(CONFIG_MTD_CEIVA) += ceiva.o
|
||||
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
|
||||
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
|
||||
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
|
||||
obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o
|
||||
obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o
|
||||
obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
|
||||
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
|
||||
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
|
||||
|
@ -1,10 +1,7 @@
|
||||
/*
|
||||
* Flash memory access on AMD Alchemy evaluation boards
|
||||
*
|
||||
* $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $
|
||||
*
|
||||
* (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
@ -18,12 +15,6 @@
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef DEBUG_RW
|
||||
#define DBG(x...) printk(x)
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MIPS_PB1000
|
||||
#define BOARD_MAP_NAME "Pb1000 Flash"
|
||||
#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
|
||||
|
@ -338,7 +338,7 @@ static int __init init_ck804xrom(void)
|
||||
}
|
||||
return -ENXIO;
|
||||
#if 0
|
||||
return pci_module_init(&ck804xrom_driver);
|
||||
return pci_register_driver(&ck804xrom_driver);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,8 @@ static int platram_probe(struct platform_device *pdev)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "got platform resource %p (0x%lx)\n", res, res->start);
|
||||
dev_dbg(&pdev->dev, "got platform resource %p (0x%llx)\n", res,
|
||||
(unsigned long long)res->start);
|
||||
|
||||
/* setup map parameters */
|
||||
|
||||
|
184
drivers/mtd/maps/pmcmsp-flash.c
Normal file
184
drivers/mtd/maps/pmcmsp-flash.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
|
||||
* Config with both CFI and JEDEC device support.
|
||||
*
|
||||
* Basically physmap.c with the addition of partitions and
|
||||
* an array of mapping info to accomodate more than one flash type per board.
|
||||
*
|
||||
* Copyright 2005-2007 PMC-Sierra, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <msp_prom.h>
|
||||
#include <msp_regs.h>
|
||||
|
||||
|
||||
static struct mtd_info **msp_flash;
|
||||
static struct mtd_partition **msp_parts;
|
||||
static struct map_info *msp_maps;
|
||||
static int fcnt;
|
||||
|
||||
#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__)
|
||||
|
||||
int __init init_msp_flash(void)
|
||||
{
|
||||
int i, j;
|
||||
int offset, coff;
|
||||
char *env;
|
||||
int pcnt;
|
||||
char flash_name[] = "flash0";
|
||||
char part_name[] = "flash0_0";
|
||||
unsigned addr, size;
|
||||
|
||||
/* If ELB is disabled by "ful-mux" mode, we can't get at flash */
|
||||
if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) &&
|
||||
(*ELB_1PC_EN_REG & SINGLE_PCCARD)) {
|
||||
printk(KERN_NOTICE "Single PC Card mode: no flash access\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* examine the prom environment for flash devices */
|
||||
for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++)
|
||||
flash_name[5] = '0' + fcnt + 1;
|
||||
|
||||
if (fcnt < 1)
|
||||
return -ENXIO;
|
||||
|
||||
printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
|
||||
msp_flash = (struct mtd_info **)kmalloc(
|
||||
fcnt * sizeof(struct map_info *), GFP_KERNEL);
|
||||
msp_parts = (struct mtd_partition **)kmalloc(
|
||||
fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
|
||||
msp_maps = (struct map_info *)kmalloc(
|
||||
fcnt * sizeof(struct mtd_info), GFP_KERNEL);
|
||||
memset(msp_maps, 0, fcnt * sizeof(struct mtd_info));
|
||||
|
||||
/* loop over the flash devices, initializing each */
|
||||
for (i = 0; i < fcnt; i++) {
|
||||
/* examine the prom environment for flash partititions */
|
||||
part_name[5] = '0' + i;
|
||||
part_name[7] = '0';
|
||||
for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++)
|
||||
part_name[7] = '0' + pcnt + 1;
|
||||
|
||||
if (pcnt == 0) {
|
||||
printk(KERN_NOTICE "Skipping flash device %d "
|
||||
"(no partitions defined)\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
msp_parts[i] = (struct mtd_partition *)kmalloc(
|
||||
pcnt * sizeof(struct mtd_partition), GFP_KERNEL);
|
||||
memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition));
|
||||
|
||||
/* now initialize the devices proper */
|
||||
flash_name[5] = '0' + i;
|
||||
env = prom_getenv(flash_name);
|
||||
|
||||
if (sscanf(env, "%x:%x", &addr, &size) < 2)
|
||||
return -ENXIO;
|
||||
addr = CPHYSADDR(addr);
|
||||
|
||||
printk(KERN_NOTICE
|
||||
"MSP flash device \"%s\": 0x%08x at 0x%08x\n",
|
||||
flash_name, size, addr);
|
||||
/* This must matchs the actual size of the flash chip */
|
||||
msp_maps[i].size = size;
|
||||
msp_maps[i].phys = addr;
|
||||
|
||||
/*
|
||||
* Platforms have a specific limit of the size of memory
|
||||
* which may be mapped for flash:
|
||||
*/
|
||||
if (size > CONFIG_MSP_FLASH_MAP_LIMIT)
|
||||
size = CONFIG_MSP_FLASH_MAP_LIMIT;
|
||||
msp_maps[i].virt = ioremap(addr, size);
|
||||
msp_maps[i].bankwidth = 1;
|
||||
msp_maps[i].name = strncpy(kmalloc(7, GFP_KERNEL),
|
||||
flash_name, 7);
|
||||
|
||||
if (msp_maps[i].virt == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
for (j = 0; j < pcnt; j++) {
|
||||
part_name[5] = '0' + i;
|
||||
part_name[7] = '0' + j;
|
||||
|
||||
env = prom_getenv(part_name);
|
||||
|
||||
if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2)
|
||||
return -ENXIO;
|
||||
|
||||
msp_parts[i][j].size = size;
|
||||
msp_parts[i][j].offset = offset;
|
||||
msp_parts[i][j].name = env + coff;
|
||||
}
|
||||
|
||||
/* now probe and add the device */
|
||||
simple_map_init(&msp_maps[i]);
|
||||
msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]);
|
||||
if (msp_flash[i]) {
|
||||
msp_flash[i]->owner = THIS_MODULE;
|
||||
add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt);
|
||||
} else {
|
||||
printk(KERN_ERR "map probe failed for flash\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_msp_flash(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(msp_flash) / sizeof(struct mtd_info **); i++) {
|
||||
del_mtd_partitions(msp_flash[i]);
|
||||
map_destroy(msp_flash[i]);
|
||||
iounmap((void *)msp_maps[i].virt);
|
||||
|
||||
/* free the memory */
|
||||
kfree(msp_maps[i].name);
|
||||
kfree(msp_parts[i]);
|
||||
}
|
||||
|
||||
kfree(msp_flash);
|
||||
kfree(msp_parts);
|
||||
kfree(msp_maps);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("PMC-Sierra, Inc");
|
||||
MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(init_msp_flash);
|
||||
module_exit(cleanup_msp_flash);
|
105
drivers/mtd/maps/pmcmsp-ramroot.c
Normal file
105
drivers/mtd/maps/pmcmsp-ramroot.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Mapping of the rootfs in a physical region of memory
|
||||
*
|
||||
* Copyright (C) 2005-2007 PMC-Sierra Inc.
|
||||
* Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/root_dev.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/map.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <msp_prom.h>
|
||||
|
||||
static struct mtd_info *rr_mtd;
|
||||
|
||||
struct map_info rr_map = {
|
||||
.name = "ramroot",
|
||||
.bankwidth = 4,
|
||||
};
|
||||
|
||||
static int __init init_rrmap(void)
|
||||
{
|
||||
void *ramroot_start;
|
||||
unsigned long ramroot_size;
|
||||
|
||||
/* Check for supported rootfs types */
|
||||
if (get_ramroot(&ramroot_start, &ramroot_size)) {
|
||||
rr_map.phys = CPHYSADDR(ramroot_start);
|
||||
rr_map.size = ramroot_size;
|
||||
|
||||
printk(KERN_NOTICE
|
||||
"PMC embedded root device: 0x%08lx @ 0x%08lx\n",
|
||||
rr_map.size, (unsigned long)rr_map.phys);
|
||||
} else {
|
||||
printk(KERN_ERR
|
||||
"init_rrmap: no supported embedded rootfs detected!\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* Map rootfs to I/O space for block device driver */
|
||||
rr_map.virt = ioremap(rr_map.phys, rr_map.size);
|
||||
if (!rr_map.virt) {
|
||||
printk(KERN_ERR "Failed to ioremap\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
simple_map_init(&rr_map);
|
||||
|
||||
rr_mtd = do_map_probe("map_ram", &rr_map);
|
||||
if (rr_mtd) {
|
||||
rr_mtd->owner = THIS_MODULE;
|
||||
|
||||
add_mtd_device(rr_mtd);
|
||||
ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
iounmap(rr_map.virt);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static void __exit cleanup_rrmap(void)
|
||||
{
|
||||
del_mtd_device(rr_mtd);
|
||||
map_destroy(rr_mtd);
|
||||
|
||||
iounmap(rr_map.virt);
|
||||
rr_map.virt = NULL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("PMC-Sierra, Inc");
|
||||
MODULE_DESCRIPTION("MTD map driver for embedded PMC-Sierra MSP filesystem");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(init_rrmap);
|
||||
module_exit(cleanup_rrmap);
|
@ -20,6 +20,7 @@
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static LIST_HEAD(blktrans_majors);
|
||||
@ -28,9 +29,7 @@ extern struct mutex mtd_table_mutex;
|
||||
extern struct mtd_info *mtd_table[];
|
||||
|
||||
struct mtd_blkcore_priv {
|
||||
struct completion thread_dead;
|
||||
int exiting;
|
||||
wait_queue_head_t thread_wq;
|
||||
struct task_struct *thread;
|
||||
struct request_queue *rq;
|
||||
spinlock_t queue_lock;
|
||||
};
|
||||
@ -83,38 +82,19 @@ static int mtd_blktrans_thread(void *arg)
|
||||
/* we might get involved when memory gets low, so use PF_MEMALLOC */
|
||||
current->flags |= PF_MEMALLOC | PF_NOFREEZE;
|
||||
|
||||
daemonize("%sd", tr->name);
|
||||
|
||||
/* daemonize() doesn't do this for us since some kernel threads
|
||||
actually want to deal with signals. We can't just call
|
||||
exit_sighand() since that'll cause an oops when we finally
|
||||
do exit. */
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
sigfillset(¤t->blocked);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
spin_lock_irq(rq->queue_lock);
|
||||
|
||||
while (!tr->blkcore_priv->exiting) {
|
||||
while (!kthread_should_stop()) {
|
||||
struct request *req;
|
||||
struct mtd_blktrans_dev *dev;
|
||||
int res = 0;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
req = elv_next_request(rq);
|
||||
|
||||
if (!req) {
|
||||
add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
spin_unlock_irq(rq->queue_lock);
|
||||
|
||||
schedule();
|
||||
remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
|
||||
|
||||
spin_lock_irq(rq->queue_lock);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -133,13 +113,13 @@ static int mtd_blktrans_thread(void *arg)
|
||||
}
|
||||
spin_unlock_irq(rq->queue_lock);
|
||||
|
||||
complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtd_blktrans_request(struct request_queue *rq)
|
||||
{
|
||||
struct mtd_blktrans_ops *tr = rq->queuedata;
|
||||
wake_up(&tr->blkcore_priv->thread_wq);
|
||||
wake_up_process(tr->blkcore_priv->thread);
|
||||
}
|
||||
|
||||
|
||||
@ -388,8 +368,6 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
||||
return ret;
|
||||
}
|
||||
spin_lock_init(&tr->blkcore_priv->queue_lock);
|
||||
init_completion(&tr->blkcore_priv->thread_dead);
|
||||
init_waitqueue_head(&tr->blkcore_priv->thread_wq);
|
||||
|
||||
tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
|
||||
if (!tr->blkcore_priv->rq) {
|
||||
@ -403,13 +381,14 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
||||
blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
|
||||
tr->blkshift = ffs(tr->blksize) - 1;
|
||||
|
||||
ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
|
||||
if (ret < 0) {
|
||||
tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
|
||||
"%sd", tr->name);
|
||||
if (IS_ERR(tr->blkcore_priv->thread)) {
|
||||
blk_cleanup_queue(tr->blkcore_priv->rq);
|
||||
unregister_blkdev(tr->major, tr->name);
|
||||
kfree(tr->blkcore_priv);
|
||||
mutex_unlock(&mtd_table_mutex);
|
||||
return ret;
|
||||
return PTR_ERR(tr->blkcore_priv->thread);
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&tr->devs);
|
||||
@ -432,9 +411,7 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
||||
mutex_lock(&mtd_table_mutex);
|
||||
|
||||
/* Clean up the kernel thread */
|
||||
tr->blkcore_priv->exiting = 1;
|
||||
wake_up(&tr->blkcore_priv->thread_wq);
|
||||
wait_for_completion(&tr->blkcore_priv->thread_dead);
|
||||
kthread_stop(tr->blkcore_priv->thread);
|
||||
|
||||
/* Remove it from the list of active majors */
|
||||
list_del(&tr->list);
|
||||
|
@ -553,7 +553,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||
ops.datbuf = NULL;
|
||||
ops.mode = MTD_OOB_PLACE;
|
||||
|
||||
if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
|
||||
if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
|
||||
return -EINVAL;
|
||||
|
||||
ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
|
||||
|
@ -1,10 +1,7 @@
|
||||
# drivers/mtd/nand/Kconfig
|
||||
# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $
|
||||
|
||||
menu "NAND Flash Device Drivers"
|
||||
depends on MTD!=n
|
||||
|
||||
config MTD_NAND
|
||||
menuconfig MTD_NAND
|
||||
tristate "NAND Device Support"
|
||||
depends on MTD
|
||||
select MTD_NAND_IDS
|
||||
@ -13,9 +10,10 @@ config MTD_NAND
|
||||
devices. For further information see
|
||||
<http://www.linux-mtd.infradead.org/doc/nand.html>.
|
||||
|
||||
if MTD_NAND
|
||||
|
||||
config MTD_NAND_VERIFY_WRITE
|
||||
bool "Verify NAND page writes"
|
||||
depends on MTD_NAND
|
||||
help
|
||||
This adds an extra check when data is written to the flash. The
|
||||
NAND flash device internally checks only bits transitioning
|
||||
@ -25,53 +23,61 @@ config MTD_NAND_VERIFY_WRITE
|
||||
|
||||
config MTD_NAND_ECC_SMC
|
||||
bool "NAND ECC Smart Media byte order"
|
||||
depends on MTD_NAND
|
||||
default n
|
||||
help
|
||||
Software ECC according to the Smart Media Specification.
|
||||
The original Linux implementation had byte 0 and 1 swapped.
|
||||
|
||||
config MTD_NAND_MUSEUM_IDS
|
||||
bool "Enable chip ids for obsolete ancient NAND devices"
|
||||
depends on MTD_NAND
|
||||
default n
|
||||
help
|
||||
Enable this option only when your board has first generation
|
||||
NAND chips (page size 256 byte, erase size 4-8KiB). The IDs
|
||||
of these chips were reused by later, larger chips.
|
||||
|
||||
config MTD_NAND_AUTCPU12
|
||||
tristate "SmartMediaCard on autronix autcpu12 board"
|
||||
depends on MTD_NAND && ARCH_AUTCPU12
|
||||
depends on ARCH_AUTCPU12
|
||||
help
|
||||
This enables the driver for the autronix autcpu12 board to
|
||||
access the SmartMediaCard.
|
||||
|
||||
config MTD_NAND_EDB7312
|
||||
tristate "Support for Cirrus Logic EBD7312 evaluation board"
|
||||
depends on MTD_NAND && ARCH_EDB7312
|
||||
depends on ARCH_EDB7312
|
||||
help
|
||||
This enables the driver for the Cirrus Logic EBD7312 evaluation
|
||||
board to access the onboard NAND Flash.
|
||||
|
||||
config MTD_NAND_H1900
|
||||
tristate "iPAQ H1900 flash"
|
||||
depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS
|
||||
depends on ARCH_PXA && MTD_PARTITIONS
|
||||
help
|
||||
This enables the driver for the iPAQ h1900 flash.
|
||||
|
||||
config MTD_NAND_SPIA
|
||||
tristate "NAND Flash device on SPIA board"
|
||||
depends on ARCH_P720T && MTD_NAND
|
||||
depends on ARCH_P720T
|
||||
help
|
||||
If you had to ask, you don't have one. Say 'N'.
|
||||
|
||||
config MTD_NAND_AMS_DELTA
|
||||
tristate "NAND Flash device on Amstrad E3"
|
||||
depends on MACH_AMS_DELTA && MTD_NAND
|
||||
depends on MACH_AMS_DELTA
|
||||
help
|
||||
Support for NAND flash on Amstrad E3 (Delta).
|
||||
|
||||
config MTD_NAND_TOTO
|
||||
tristate "NAND Flash device on TOTO board"
|
||||
depends on ARCH_OMAP && MTD_NAND && BROKEN
|
||||
depends on ARCH_OMAP && BROKEN
|
||||
help
|
||||
Support for NAND flash on Texas Instruments Toto platform.
|
||||
|
||||
config MTD_NAND_TS7250
|
||||
tristate "NAND Flash device on TS-7250 board"
|
||||
depends on MACH_TS72XX && MTD_NAND
|
||||
depends on MACH_TS72XX
|
||||
help
|
||||
Support for NAND flash on Technologic Systems TS-7250 platform.
|
||||
|
||||
@ -80,14 +86,14 @@ config MTD_NAND_IDS
|
||||
|
||||
config MTD_NAND_AU1550
|
||||
tristate "Au1550/1200 NAND support"
|
||||
depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND
|
||||
depends on SOC_AU1200 || SOC_AU1550
|
||||
help
|
||||
This enables the driver for the NAND flash controller on the
|
||||
AMD/Alchemy 1550 SOC.
|
||||
|
||||
config MTD_NAND_RTC_FROM4
|
||||
tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
|
||||
depends on MTD_NAND && SH_SOLUTION_ENGINE
|
||||
depends on SH_SOLUTION_ENGINE
|
||||
select REED_SOLOMON
|
||||
select REED_SOLOMON_DEC8
|
||||
select BITREVERSE
|
||||
@ -97,13 +103,13 @@ config MTD_NAND_RTC_FROM4
|
||||
|
||||
config MTD_NAND_PPCHAMELEONEVB
|
||||
tristate "NAND Flash device on PPChameleonEVB board"
|
||||
depends on PPCHAMELEONEVB && MTD_NAND && BROKEN
|
||||
depends on PPCHAMELEONEVB && BROKEN
|
||||
help
|
||||
This enables the NAND flash driver on the PPChameleon EVB Board.
|
||||
|
||||
config MTD_NAND_S3C2410
|
||||
tristate "NAND Flash support for S3C2410/S3C2440 SoC"
|
||||
depends on ARCH_S3C2410 && MTD_NAND
|
||||
depends on ARCH_S3C2410
|
||||
help
|
||||
This enables the NAND flash controller on the S3C2410 and S3C2440
|
||||
SoCs
|
||||
@ -128,7 +134,7 @@ config MTD_NAND_S3C2410_HWECC
|
||||
|
||||
config MTD_NAND_NDFC
|
||||
tristate "NDFC NanD Flash Controller"
|
||||
depends on MTD_NAND && 44x
|
||||
depends on 44x
|
||||
select MTD_NAND_ECC_SMC
|
||||
help
|
||||
NDFC Nand Flash Controllers are integrated in EP44x SoCs
|
||||
@ -145,7 +151,7 @@ config MTD_NAND_S3C2410_CLKSTOP
|
||||
|
||||
config MTD_NAND_DISKONCHIP
|
||||
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
|
||||
depends on MTD_NAND && EXPERIMENTAL
|
||||
depends on EXPERIMENTAL
|
||||
select REED_SOLOMON
|
||||
select REED_SOLOMON_DEC16
|
||||
help
|
||||
@ -215,11 +221,11 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
|
||||
|
||||
config MTD_NAND_SHARPSL
|
||||
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
|
||||
depends on MTD_NAND && ARCH_PXA
|
||||
depends on ARCH_PXA
|
||||
|
||||
config MTD_NAND_BASLER_EXCITE
|
||||
tristate "Support for NAND Flash on Basler eXcite"
|
||||
depends on MTD_NAND && BASLER_EXCITE
|
||||
depends on BASLER_EXCITE
|
||||
help
|
||||
This enables the driver for the NAND flash device found on the
|
||||
Basler eXcite Smart Camera. If built as a module, the driver
|
||||
@ -227,14 +233,14 @@ config MTD_NAND_BASLER_EXCITE
|
||||
|
||||
config MTD_NAND_CAFE
|
||||
tristate "NAND support for OLPC CAFÉ chip"
|
||||
depends on MTD_NAND && PCI
|
||||
depends on PCI
|
||||
help
|
||||
Use NAND flash attached to the CAFÉ chip designed for the $100
|
||||
laptop.
|
||||
|
||||
config MTD_NAND_CS553X
|
||||
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
|
||||
depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH)
|
||||
depends on X86_32 && (X86_PC || X86_GENERICARCH)
|
||||
help
|
||||
The CS553x companion chips for the AMD Geode processor
|
||||
include NAND flash controllers with built-in hardware ECC
|
||||
@ -247,16 +253,21 @@ config MTD_NAND_CS553X
|
||||
|
||||
config MTD_NAND_AT91
|
||||
bool "Support for NAND Flash / SmartMedia on AT91"
|
||||
depends on MTD_NAND && ARCH_AT91
|
||||
depends on ARCH_AT91
|
||||
help
|
||||
Enables support for NAND Flash / Smart Media Card interface
|
||||
on Atmel AT91 processors.
|
||||
|
||||
config MTD_NAND_CM_X270
|
||||
tristate "Support for NAND Flash on CM-X270 modules"
|
||||
depends on MTD_NAND && MACH_ARMCORE
|
||||
|
||||
|
||||
config MTD_NAND_NANDSIM
|
||||
tristate "Support for NAND Flash Simulator"
|
||||
depends on MTD_NAND && MTD_PARTITIONS
|
||||
depends on MTD_PARTITIONS
|
||||
help
|
||||
The simulator may simulate various NAND flash chips for the
|
||||
MTD nand layer.
|
||||
|
||||
endmenu
|
||||
endif # MTD_NAND
|
||||
|
@ -24,6 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
|
||||
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
|
||||
obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
|
||||
|
||||
nand-objs := nand_base.o nand_bbt.o
|
||||
|
@ -530,7 +530,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
|
||||
{
|
||||
struct mtd_info *mtd;
|
||||
struct cafe_priv *cafe;
|
||||
uint32_t timing1, timing2, timing3;
|
||||
uint32_t ctrl;
|
||||
int err = 0;
|
||||
|
||||
@ -587,21 +586,19 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
if (numtimings == 3) {
|
||||
timing1 = timing[0];
|
||||
timing2 = timing[1];
|
||||
timing3 = timing[2];
|
||||
cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
|
||||
timing1, timing2, timing3);
|
||||
timing[0], timing[1], timing[2]);
|
||||
} else {
|
||||
timing1 = cafe_readl(cafe, NAND_TIMING1);
|
||||
timing2 = cafe_readl(cafe, NAND_TIMING2);
|
||||
timing3 = cafe_readl(cafe, NAND_TIMING3);
|
||||
timing[0] = cafe_readl(cafe, NAND_TIMING1);
|
||||
timing[1] = cafe_readl(cafe, NAND_TIMING2);
|
||||
timing[2] = cafe_readl(cafe, NAND_TIMING3);
|
||||
|
||||
if (timing1 | timing2 | timing3) {
|
||||
cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3);
|
||||
if (timing[0] | timing[1] | timing[2]) {
|
||||
cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
|
||||
timing[0], timing[1], timing[2]);
|
||||
} else {
|
||||
dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
|
||||
timing1 = timing2 = timing3 = 0xffffffff;
|
||||
timing[0] = timing[1] = timing[2] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,9 +606,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
|
||||
cafe_writel(cafe, 1, NAND_RESET);
|
||||
cafe_writel(cafe, 0, NAND_RESET);
|
||||
|
||||
cafe_writel(cafe, timing1, NAND_TIMING1);
|
||||
cafe_writel(cafe, timing2, NAND_TIMING2);
|
||||
cafe_writel(cafe, timing3, NAND_TIMING3);
|
||||
cafe_writel(cafe, timing[0], NAND_TIMING1);
|
||||
cafe_writel(cafe, timing[1], NAND_TIMING2);
|
||||
cafe_writel(cafe, timing[2], NAND_TIMING3);
|
||||
|
||||
cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
|
||||
err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
|
||||
|
267
drivers/mtd/nand/cmx270_nand.c
Normal file
267
drivers/mtd/nand/cmx270_nand.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* linux/drivers/mtd/nand/cmx270-nand.c
|
||||
*
|
||||
* Copyright (C) 2006 Compulab, Ltd.
|
||||
* Mike Rapoport <mike@compulab.co.il>
|
||||
*
|
||||
* Derived from drivers/mtd/nand/h1910.c
|
||||
* Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
|
||||
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Overview:
|
||||
* This is a device driver for the NAND flash device found on the
|
||||
* CM-X270 board.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
|
||||
#define GPIO_NAND_CS (11)
|
||||
#define GPIO_NAND_RB (89)
|
||||
|
||||
/* This macro needed to ensure in-order operation of GPIO and local
|
||||
* bus. Without both asm command and dummy uncached read there're
|
||||
* states when NAND access is broken. I've looked for such macro(s) in
|
||||
* include/asm-arm but found nothing approptiate.
|
||||
* dmac_clean_range is close, but is makes cache invalidation
|
||||
* unnecessary here and it cannot be used in module
|
||||
*/
|
||||
#define DRAIN_WB() \
|
||||
do { \
|
||||
unsigned char dummy; \
|
||||
asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); \
|
||||
dummy=*((unsigned char*)UNCACHED_ADDR); \
|
||||
} while(0)
|
||||
|
||||
/* MTD structure for CM-X270 board */
|
||||
static struct mtd_info *cmx270_nand_mtd;
|
||||
|
||||
/* remaped IO address of the device */
|
||||
static void __iomem *cmx270_nand_io;
|
||||
|
||||
/*
|
||||
* Define static partitions for flash device
|
||||
*/
|
||||
static struct mtd_partition partition_info[] = {
|
||||
[0] = {
|
||||
.name = "cmx270-0",
|
||||
.offset = 0,
|
||||
.size = MTDPART_SIZ_FULL
|
||||
}
|
||||
};
|
||||
#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
|
||||
|
||||
const char *part_probes[] = { "cmdlinepart", NULL };
|
||||
|
||||
static u_char cmx270_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
return (readl(this->IO_ADDR_R) >> 16);
|
||||
}
|
||||
|
||||
static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
writel((*buf++ << 16), this->IO_ADDR_W);
|
||||
}
|
||||
|
||||
static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
*buf++ = readl(this->IO_ADDR_R) >> 16;
|
||||
}
|
||||
|
||||
static int cmx270_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
if (buf[i] != (u_char)(readl(this->IO_ADDR_R) >> 16))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void nand_cs_on(void)
|
||||
{
|
||||
GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
|
||||
}
|
||||
|
||||
static void nand_cs_off(void)
|
||||
{
|
||||
DRAIN_WB();
|
||||
|
||||
GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
|
||||
}
|
||||
|
||||
/*
|
||||
* hardware specific access to control-lines
|
||||
*/
|
||||
static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip* this = mtd->priv;
|
||||
unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
|
||||
|
||||
DRAIN_WB();
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if ( ctrl & NAND_ALE )
|
||||
nandaddr |= (1 << 3);
|
||||
else
|
||||
nandaddr &= ~(1 << 3);
|
||||
if ( ctrl & NAND_CLE )
|
||||
nandaddr |= (1 << 2);
|
||||
else
|
||||
nandaddr &= ~(1 << 2);
|
||||
if ( ctrl & NAND_NCE )
|
||||
nand_cs_on();
|
||||
else
|
||||
nand_cs_off();
|
||||
}
|
||||
|
||||
DRAIN_WB();
|
||||
this->IO_ADDR_W = (void __iomem*)nandaddr;
|
||||
if (dat != NAND_CMD_NONE)
|
||||
writel((dat << 16), this->IO_ADDR_W);
|
||||
|
||||
DRAIN_WB();
|
||||
}
|
||||
|
||||
/*
|
||||
* read device ready pin
|
||||
*/
|
||||
static int cmx270_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
DRAIN_WB();
|
||||
|
||||
return (GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB));
|
||||
}
|
||||
|
||||
/*
|
||||
* Main initialization routine
|
||||
*/
|
||||
static int cmx270_init(void)
|
||||
{
|
||||
struct nand_chip *this;
|
||||
const char *part_type;
|
||||
struct mtd_partition *mtd_parts;
|
||||
int mtd_parts_nb = 0;
|
||||
int ret;
|
||||
|
||||
/* Allocate memory for MTD device structure and private data */
|
||||
cmx270_nand_mtd = kzalloc(sizeof(struct mtd_info) +
|
||||
sizeof(struct nand_chip),
|
||||
GFP_KERNEL);
|
||||
if (!cmx270_nand_mtd) {
|
||||
printk("Unable to allocate CM-X270 NAND MTD device structure.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
|
||||
if (!cmx270_nand_io) {
|
||||
printk("Unable to ioremap NAND device\n");
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Get pointer to private data */
|
||||
this = (struct nand_chip *)(&cmx270_nand_mtd[1]);
|
||||
|
||||
/* Link the private data with the MTD structure */
|
||||
cmx270_nand_mtd->owner = THIS_MODULE;
|
||||
cmx270_nand_mtd->priv = this;
|
||||
|
||||
/* insert callbacks */
|
||||
this->IO_ADDR_R = cmx270_nand_io;
|
||||
this->IO_ADDR_W = cmx270_nand_io;
|
||||
this->cmd_ctrl = cmx270_hwcontrol;
|
||||
this->dev_ready = cmx270_device_ready;
|
||||
|
||||
/* 15 us command delay time */
|
||||
this->chip_delay = 20;
|
||||
this->ecc.mode = NAND_ECC_SOFT;
|
||||
|
||||
/* read/write functions */
|
||||
this->read_byte = cmx270_read_byte;
|
||||
this->read_buf = cmx270_read_buf;
|
||||
this->write_buf = cmx270_write_buf;
|
||||
this->verify_buf = cmx270_verify_buf;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
if (nand_scan (cmx270_nand_mtd, 1)) {
|
||||
printk(KERN_NOTICE "No NAND device\n");
|
||||
ret = -ENXIO;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||
mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes,
|
||||
&mtd_parts, 0);
|
||||
if (mtd_parts_nb > 0)
|
||||
part_type = "command line";
|
||||
else
|
||||
mtd_parts_nb = 0;
|
||||
#endif
|
||||
if (!mtd_parts_nb) {
|
||||
mtd_parts = partition_info;
|
||||
mtd_parts_nb = NUM_PARTITIONS;
|
||||
part_type = "static";
|
||||
}
|
||||
|
||||
/* Register the partitions */
|
||||
printk(KERN_NOTICE "Using %s partition definition\n", part_type);
|
||||
ret = add_mtd_partitions(cmx270_nand_mtd, mtd_parts, mtd_parts_nb);
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
/* Return happy */
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
iounmap(cmx270_nand_io);
|
||||
err1:
|
||||
kfree(cmx270_nand_mtd);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
module_init(cmx270_init);
|
||||
|
||||
/*
|
||||
* Clean up routine
|
||||
*/
|
||||
static void cmx270_cleanup(void)
|
||||
{
|
||||
/* Release resources, unregister device */
|
||||
nand_release(cmx270_nand_mtd);
|
||||
|
||||
iounmap(cmx270_nand_io);
|
||||
|
||||
/* Free the MTD device structure */
|
||||
kfree (cmx270_nand_mtd);
|
||||
}
|
||||
module_exit(cmx270_cleanup);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
|
||||
MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");
|
@ -312,7 +312,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||
/* Select the NAND device */
|
||||
chip->select_chip(mtd, chipnr);
|
||||
} else
|
||||
page = (int)ofs;
|
||||
page = (int)(ofs >> chip->page_shift);
|
||||
|
||||
if (chip->options & NAND_BUSWIDTH_16) {
|
||||
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
|
||||
@ -350,7 +350,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
int block, ret;
|
||||
|
||||
/* Get block number */
|
||||
block = ((int)ofs) >> chip->bbt_erase_shift;
|
||||
block = (int)(ofs >> chip->bbt_erase_shift);
|
||||
if (chip->bbt)
|
||||
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
|
||||
|
||||
@ -771,7 +771,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *ecc_code = chip->buffers->ecccode;
|
||||
int *eccpos = chip->ecc.layout->eccpos;
|
||||
|
||||
nand_read_page_raw(mtd, chip, buf);
|
||||
chip->ecc.read_page_raw(mtd, chip, buf);
|
||||
|
||||
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
|
||||
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||
@ -1426,7 +1426,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
for (i = 0; i < chip->ecc.total; i++)
|
||||
chip->oob_poi[eccpos[i]] = ecc_calc[i];
|
||||
|
||||
nand_write_page_raw(mtd, chip, buf);
|
||||
chip->ecc.write_page_raw(mtd, chip, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,6 +24,8 @@
|
||||
* 512 512 Byte page size
|
||||
*/
|
||||
struct nand_flash_dev nand_flash_ids[] = {
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
|
||||
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
|
||||
{"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
|
||||
{"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
|
||||
@ -39,6 +41,7 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||
{"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
|
||||
{"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||
#endif
|
||||
|
||||
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
|
||||
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
|
||||
@ -137,6 +140,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
|
||||
{NAND_MFR_RENESAS, "Renesas"},
|
||||
{NAND_MFR_STMICRO, "ST Micro"},
|
||||
{NAND_MFR_HYNIX, "Hynix"},
|
||||
{NAND_MFR_MICRON, "Micron"},
|
||||
{0x0, "Unknown"}
|
||||
};
|
||||
|
||||
|
@ -37,6 +37,8 @@
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
/* Default simulator parameters values */
|
||||
#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
|
||||
@ -90,6 +92,15 @@ static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH;
|
||||
static uint do_delays = CONFIG_NANDSIM_DO_DELAYS;
|
||||
static uint log = CONFIG_NANDSIM_LOG;
|
||||
static uint dbg = CONFIG_NANDSIM_DBG;
|
||||
static unsigned long parts[MAX_MTD_DEVICES];
|
||||
static unsigned int parts_num;
|
||||
static char *badblocks = NULL;
|
||||
static char *weakblocks = NULL;
|
||||
static char *weakpages = NULL;
|
||||
static unsigned int bitflips = 0;
|
||||
static char *gravepages = NULL;
|
||||
static unsigned int rptwear = 0;
|
||||
static unsigned int overridesize = 0;
|
||||
|
||||
module_param(first_id_byte, uint, 0400);
|
||||
module_param(second_id_byte, uint, 0400);
|
||||
@ -104,8 +115,16 @@ module_param(bus_width, uint, 0400);
|
||||
module_param(do_delays, uint, 0400);
|
||||
module_param(log, uint, 0400);
|
||||
module_param(dbg, uint, 0400);
|
||||
module_param_array(parts, ulong, &parts_num, 0400);
|
||||
module_param(badblocks, charp, 0400);
|
||||
module_param(weakblocks, charp, 0400);
|
||||
module_param(weakpages, charp, 0400);
|
||||
module_param(bitflips, uint, 0400);
|
||||
module_param(gravepages, charp, 0400);
|
||||
module_param(rptwear, uint, 0400);
|
||||
module_param(overridesize, uint, 0400);
|
||||
|
||||
MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
|
||||
MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
|
||||
MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
|
||||
MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command");
|
||||
MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
|
||||
@ -118,6 +137,23 @@ MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)");
|
||||
MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero");
|
||||
MODULE_PARM_DESC(log, "Perform logging if not zero");
|
||||
MODULE_PARM_DESC(dbg, "Output debug information if not zero");
|
||||
MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas");
|
||||
/* Page and erase block positions for the following parameters are independent of any partitions */
|
||||
MODULE_PARM_DESC(badblocks, "Erase blocks that are initially marked bad, separated by commas");
|
||||
MODULE_PARM_DESC(weakblocks, "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
|
||||
" separated by commas e.g. 113:2 means eb 113"
|
||||
" can be erased only twice before failing");
|
||||
MODULE_PARM_DESC(weakpages, "Weak pages [: maximum writes (defaults to 3)]"
|
||||
" separated by commas e.g. 1401:2 means page 1401"
|
||||
" can be written only twice before failing");
|
||||
MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (zero by default)");
|
||||
MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]"
|
||||
" separated by commas e.g. 1401:2 means page 1401"
|
||||
" can be read only twice before failing");
|
||||
MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero");
|
||||
MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. "
|
||||
"The size is specified in erase blocks and as the exponent of a power of two"
|
||||
" e.g. 5 means a size of 32 erase blocks");
|
||||
|
||||
/* The largest possible page size */
|
||||
#define NS_LARGEST_PAGE_SIZE 2048
|
||||
@ -131,9 +167,11 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
|
||||
#define NS_DBG(args...) \
|
||||
do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
|
||||
#define NS_WARN(args...) \
|
||||
do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0)
|
||||
do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
|
||||
#define NS_ERR(args...) \
|
||||
do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0)
|
||||
do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
|
||||
#define NS_INFO(args...) \
|
||||
do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
|
||||
|
||||
/* Busy-wait delay macros (microseconds, milliseconds) */
|
||||
#define NS_UDELAY(us) \
|
||||
@ -238,7 +276,8 @@ union ns_mem {
|
||||
* The structure which describes all the internal simulator data.
|
||||
*/
|
||||
struct nandsim {
|
||||
struct mtd_partition part;
|
||||
struct mtd_partition partitions[MAX_MTD_DEVICES];
|
||||
unsigned int nbparts;
|
||||
|
||||
uint busw; /* flash chip bus width (8 or 16) */
|
||||
u_char ids[4]; /* chip's ID bytes */
|
||||
@ -338,6 +377,38 @@ static struct nandsim_operations {
|
||||
STATE_DATAOUT, STATE_READY}}
|
||||
};
|
||||
|
||||
struct weak_block {
|
||||
struct list_head list;
|
||||
unsigned int erase_block_no;
|
||||
unsigned int max_erases;
|
||||
unsigned int erases_done;
|
||||
};
|
||||
|
||||
static LIST_HEAD(weak_blocks);
|
||||
|
||||
struct weak_page {
|
||||
struct list_head list;
|
||||
unsigned int page_no;
|
||||
unsigned int max_writes;
|
||||
unsigned int writes_done;
|
||||
};
|
||||
|
||||
static LIST_HEAD(weak_pages);
|
||||
|
||||
struct grave_page {
|
||||
struct list_head list;
|
||||
unsigned int page_no;
|
||||
unsigned int max_reads;
|
||||
unsigned int reads_done;
|
||||
};
|
||||
|
||||
static LIST_HEAD(grave_pages);
|
||||
|
||||
static unsigned long *erase_block_wear = NULL;
|
||||
static unsigned int wear_eb_count = 0;
|
||||
static unsigned long total_wear = 0;
|
||||
static unsigned int rptwear_cnt = 0;
|
||||
|
||||
/* MTD structure for NAND controller */
|
||||
static struct mtd_info *nsmtd;
|
||||
|
||||
@ -381,6 +452,13 @@ static void free_device(struct nandsim *ns)
|
||||
}
|
||||
}
|
||||
|
||||
static char *get_partition_name(int i)
|
||||
{
|
||||
char buf[64];
|
||||
sprintf(buf, "NAND simulator partition %d", i);
|
||||
return kstrdup(buf, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the nandsim structure.
|
||||
*
|
||||
@ -390,7 +468,9 @@ static int init_nandsim(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
|
||||
struct nandsim *ns = (struct nandsim *)(chip->priv);
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
u_int32_t remains;
|
||||
u_int32_t next_offset;
|
||||
|
||||
if (NS_IS_INITIALIZED(ns)) {
|
||||
NS_ERR("init_nandsim: nandsim is already initialized\n");
|
||||
@ -448,6 +528,40 @@ static int init_nandsim(struct mtd_info *mtd)
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill the partition_info structure */
|
||||
if (parts_num > ARRAY_SIZE(ns->partitions)) {
|
||||
NS_ERR("too many partitions.\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
remains = ns->geom.totsz;
|
||||
next_offset = 0;
|
||||
for (i = 0; i < parts_num; ++i) {
|
||||
unsigned long part = parts[i];
|
||||
if (!part || part > remains / ns->geom.secsz) {
|
||||
NS_ERR("bad partition size.\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
ns->partitions[i].name = get_partition_name(i);
|
||||
ns->partitions[i].offset = next_offset;
|
||||
ns->partitions[i].size = part * ns->geom.secsz;
|
||||
next_offset += ns->partitions[i].size;
|
||||
remains -= ns->partitions[i].size;
|
||||
}
|
||||
ns->nbparts = parts_num;
|
||||
if (remains) {
|
||||
if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
|
||||
NS_ERR("too many partitions.\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
ns->partitions[i].name = get_partition_name(i);
|
||||
ns->partitions[i].offset = next_offset;
|
||||
ns->partitions[i].size = remains;
|
||||
ns->nbparts += 1;
|
||||
}
|
||||
|
||||
/* Detect how many ID bytes the NAND chip outputs */
|
||||
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
|
||||
if (second_id_byte != nand_flash_ids[i].id)
|
||||
@ -474,7 +588,7 @@ static int init_nandsim(struct mtd_info *mtd)
|
||||
printk("sector address bytes: %u\n", ns->geom.secaddrbytes);
|
||||
printk("options: %#x\n", ns->options);
|
||||
|
||||
if (alloc_device(ns) != 0)
|
||||
if ((ret = alloc_device(ns)) != 0)
|
||||
goto error;
|
||||
|
||||
/* Allocate / initialize the internal buffer */
|
||||
@ -482,21 +596,17 @@ static int init_nandsim(struct mtd_info *mtd)
|
||||
if (!ns->buf.byte) {
|
||||
NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
|
||||
ns->geom.pgszoob);
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
|
||||
|
||||
/* Fill the partition_info structure */
|
||||
ns->part.name = "NAND simulator partition";
|
||||
ns->part.offset = 0;
|
||||
ns->part.size = ns->geom.totsz;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free_device(ns);
|
||||
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -510,6 +620,287 @@ static void free_nandsim(struct nandsim *ns)
|
||||
return;
|
||||
}
|
||||
|
||||
static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
|
||||
{
|
||||
char *w;
|
||||
int zero_ok;
|
||||
unsigned int erase_block_no;
|
||||
loff_t offset;
|
||||
|
||||
if (!badblocks)
|
||||
return 0;
|
||||
w = badblocks;
|
||||
do {
|
||||
zero_ok = (*w == '0' ? 1 : 0);
|
||||
erase_block_no = simple_strtoul(w, &w, 0);
|
||||
if (!zero_ok && !erase_block_no) {
|
||||
NS_ERR("invalid badblocks.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
offset = erase_block_no * ns->geom.secsz;
|
||||
if (mtd->block_markbad(mtd, offset)) {
|
||||
NS_ERR("invalid badblocks.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (*w == ',')
|
||||
w += 1;
|
||||
} while (*w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_weakblocks(void)
|
||||
{
|
||||
char *w;
|
||||
int zero_ok;
|
||||
unsigned int erase_block_no;
|
||||
unsigned int max_erases;
|
||||
struct weak_block *wb;
|
||||
|
||||
if (!weakblocks)
|
||||
return 0;
|
||||
w = weakblocks;
|
||||
do {
|
||||
zero_ok = (*w == '0' ? 1 : 0);
|
||||
erase_block_no = simple_strtoul(w, &w, 0);
|
||||
if (!zero_ok && !erase_block_no) {
|
||||
NS_ERR("invalid weakblocks.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
max_erases = 3;
|
||||
if (*w == ':') {
|
||||
w += 1;
|
||||
max_erases = simple_strtoul(w, &w, 0);
|
||||
}
|
||||
if (*w == ',')
|
||||
w += 1;
|
||||
wb = kzalloc(sizeof(*wb), GFP_KERNEL);
|
||||
if (!wb) {
|
||||
NS_ERR("unable to allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
wb->erase_block_no = erase_block_no;
|
||||
wb->max_erases = max_erases;
|
||||
list_add(&wb->list, &weak_blocks);
|
||||
} while (*w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int erase_error(unsigned int erase_block_no)
|
||||
{
|
||||
struct weak_block *wb;
|
||||
|
||||
list_for_each_entry(wb, &weak_blocks, list)
|
||||
if (wb->erase_block_no == erase_block_no) {
|
||||
if (wb->erases_done >= wb->max_erases)
|
||||
return 1;
|
||||
wb->erases_done += 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_weakpages(void)
|
||||
{
|
||||
char *w;
|
||||
int zero_ok;
|
||||
unsigned int page_no;
|
||||
unsigned int max_writes;
|
||||
struct weak_page *wp;
|
||||
|
||||
if (!weakpages)
|
||||
return 0;
|
||||
w = weakpages;
|
||||
do {
|
||||
zero_ok = (*w == '0' ? 1 : 0);
|
||||
page_no = simple_strtoul(w, &w, 0);
|
||||
if (!zero_ok && !page_no) {
|
||||
NS_ERR("invalid weakpagess.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
max_writes = 3;
|
||||
if (*w == ':') {
|
||||
w += 1;
|
||||
max_writes = simple_strtoul(w, &w, 0);
|
||||
}
|
||||
if (*w == ',')
|
||||
w += 1;
|
||||
wp = kzalloc(sizeof(*wp), GFP_KERNEL);
|
||||
if (!wp) {
|
||||
NS_ERR("unable to allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
wp->page_no = page_no;
|
||||
wp->max_writes = max_writes;
|
||||
list_add(&wp->list, &weak_pages);
|
||||
} while (*w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_error(unsigned int page_no)
|
||||
{
|
||||
struct weak_page *wp;
|
||||
|
||||
list_for_each_entry(wp, &weak_pages, list)
|
||||
if (wp->page_no == page_no) {
|
||||
if (wp->writes_done >= wp->max_writes)
|
||||
return 1;
|
||||
wp->writes_done += 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_gravepages(void)
|
||||
{
|
||||
char *g;
|
||||
int zero_ok;
|
||||
unsigned int page_no;
|
||||
unsigned int max_reads;
|
||||
struct grave_page *gp;
|
||||
|
||||
if (!gravepages)
|
||||
return 0;
|
||||
g = gravepages;
|
||||
do {
|
||||
zero_ok = (*g == '0' ? 1 : 0);
|
||||
page_no = simple_strtoul(g, &g, 0);
|
||||
if (!zero_ok && !page_no) {
|
||||
NS_ERR("invalid gravepagess.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
max_reads = 3;
|
||||
if (*g == ':') {
|
||||
g += 1;
|
||||
max_reads = simple_strtoul(g, &g, 0);
|
||||
}
|
||||
if (*g == ',')
|
||||
g += 1;
|
||||
gp = kzalloc(sizeof(*gp), GFP_KERNEL);
|
||||
if (!gp) {
|
||||
NS_ERR("unable to allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
gp->page_no = page_no;
|
||||
gp->max_reads = max_reads;
|
||||
list_add(&gp->list, &grave_pages);
|
||||
} while (*g);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_error(unsigned int page_no)
|
||||
{
|
||||
struct grave_page *gp;
|
||||
|
||||
list_for_each_entry(gp, &grave_pages, list)
|
||||
if (gp->page_no == page_no) {
|
||||
if (gp->reads_done >= gp->max_reads)
|
||||
return 1;
|
||||
gp->reads_done += 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_lists(void)
|
||||
{
|
||||
struct list_head *pos, *n;
|
||||
list_for_each_safe(pos, n, &weak_blocks) {
|
||||
list_del(pos);
|
||||
kfree(list_entry(pos, struct weak_block, list));
|
||||
}
|
||||
list_for_each_safe(pos, n, &weak_pages) {
|
||||
list_del(pos);
|
||||
kfree(list_entry(pos, struct weak_page, list));
|
||||
}
|
||||
list_for_each_safe(pos, n, &grave_pages) {
|
||||
list_del(pos);
|
||||
kfree(list_entry(pos, struct grave_page, list));
|
||||
}
|
||||
kfree(erase_block_wear);
|
||||
}
|
||||
|
||||
static int setup_wear_reporting(struct mtd_info *mtd)
|
||||
{
|
||||
size_t mem;
|
||||
|
||||
if (!rptwear)
|
||||
return 0;
|
||||
wear_eb_count = mtd->size / mtd->erasesize;
|
||||
mem = wear_eb_count * sizeof(unsigned long);
|
||||
if (mem / sizeof(unsigned long) != wear_eb_count) {
|
||||
NS_ERR("Too many erase blocks for wear reporting\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
erase_block_wear = kzalloc(mem, GFP_KERNEL);
|
||||
if (!erase_block_wear) {
|
||||
NS_ERR("Too many erase blocks for wear reporting\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_wear(unsigned int erase_block_no)
|
||||
{
|
||||
unsigned long wmin = -1, wmax = 0, avg;
|
||||
unsigned long deciles[10], decile_max[10], tot = 0;
|
||||
unsigned int i;
|
||||
|
||||
if (!erase_block_wear)
|
||||
return;
|
||||
total_wear += 1;
|
||||
if (total_wear == 0)
|
||||
NS_ERR("Erase counter total overflow\n");
|
||||
erase_block_wear[erase_block_no] += 1;
|
||||
if (erase_block_wear[erase_block_no] == 0)
|
||||
NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
|
||||
rptwear_cnt += 1;
|
||||
if (rptwear_cnt < rptwear)
|
||||
return;
|
||||
rptwear_cnt = 0;
|
||||
/* Calc wear stats */
|
||||
for (i = 0; i < wear_eb_count; ++i) {
|
||||
unsigned long wear = erase_block_wear[i];
|
||||
if (wear < wmin)
|
||||
wmin = wear;
|
||||
if (wear > wmax)
|
||||
wmax = wear;
|
||||
tot += wear;
|
||||
}
|
||||
for (i = 0; i < 9; ++i) {
|
||||
deciles[i] = 0;
|
||||
decile_max[i] = (wmax * (i + 1) + 5) / 10;
|
||||
}
|
||||
deciles[9] = 0;
|
||||
decile_max[9] = wmax;
|
||||
for (i = 0; i < wear_eb_count; ++i) {
|
||||
int d;
|
||||
unsigned long wear = erase_block_wear[i];
|
||||
for (d = 0; d < 10; ++d)
|
||||
if (wear <= decile_max[d]) {
|
||||
deciles[d] += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
avg = tot / wear_eb_count;
|
||||
/* Output wear report */
|
||||
NS_INFO("*** Wear Report ***\n");
|
||||
NS_INFO("Total numbers of erases: %lu\n", tot);
|
||||
NS_INFO("Number of erase blocks: %u\n", wear_eb_count);
|
||||
NS_INFO("Average number of erases: %lu\n", avg);
|
||||
NS_INFO("Maximum number of erases: %lu\n", wmax);
|
||||
NS_INFO("Minimum number of erases: %lu\n", wmin);
|
||||
for (i = 0; i < 10; ++i) {
|
||||
unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
|
||||
if (from > decile_max[i])
|
||||
continue;
|
||||
NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
|
||||
from,
|
||||
decile_max[i],
|
||||
deciles[i]);
|
||||
}
|
||||
NS_INFO("*** End of Wear Report ***\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the string representation of 'state' state.
|
||||
*/
|
||||
@ -822,9 +1213,31 @@ static void read_page(struct nandsim *ns, int num)
|
||||
NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
|
||||
memset(ns->buf.byte, 0xFF, num);
|
||||
} else {
|
||||
unsigned int page_no = ns->regs.row;
|
||||
NS_DBG("read_page: page %d allocated, reading from %d\n",
|
||||
ns->regs.row, ns->regs.column + ns->regs.off);
|
||||
if (read_error(page_no)) {
|
||||
int i;
|
||||
memset(ns->buf.byte, 0xFF, num);
|
||||
for (i = 0; i < num; ++i)
|
||||
ns->buf.byte[i] = random32();
|
||||
NS_WARN("simulating read error in page %u\n", page_no);
|
||||
return;
|
||||
}
|
||||
memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
|
||||
if (bitflips && random32() < (1 << 22)) {
|
||||
int flips = 1;
|
||||
if (bitflips > 1)
|
||||
flips = (random32() % (int) bitflips) + 1;
|
||||
while (flips--) {
|
||||
int pos = random32() % (num * 8);
|
||||
ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
|
||||
NS_WARN("read_page: flipping bit %d in page %d "
|
||||
"reading from %d ecc: corrected=%u failed=%u\n",
|
||||
pos, ns->regs.row, ns->regs.column + ns->regs.off,
|
||||
nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -883,6 +1296,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
|
||||
{
|
||||
int num;
|
||||
int busdiv = ns->busw == 8 ? 1 : 2;
|
||||
unsigned int erase_block_no, page_no;
|
||||
|
||||
action &= ACTION_MASK;
|
||||
|
||||
@ -942,14 +1356,24 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
|
||||
8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
|
||||
ns->regs.column = 0;
|
||||
|
||||
erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
|
||||
|
||||
NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
|
||||
ns->regs.row, NS_RAW_OFFSET(ns));
|
||||
NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
|
||||
NS_LOG("erase sector %u\n", erase_block_no);
|
||||
|
||||
erase_sector(ns);
|
||||
|
||||
NS_MDELAY(erase_delay);
|
||||
|
||||
if (erase_block_wear)
|
||||
update_wear(erase_block_no);
|
||||
|
||||
if (erase_error(erase_block_no)) {
|
||||
NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ACTION_PRGPAGE:
|
||||
@ -972,6 +1396,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
|
||||
if (prog_page(ns, num) == -1)
|
||||
return -1;
|
||||
|
||||
page_no = ns->regs.row;
|
||||
|
||||
NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
|
||||
num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
|
||||
NS_LOG("programm page %d\n", ns->regs.row);
|
||||
@ -979,6 +1405,11 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
|
||||
NS_UDELAY(programm_delay);
|
||||
NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
|
||||
|
||||
if (write_error(page_no)) {
|
||||
NS_WARN("simulating write failure in page %u\n", page_no);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ACTION_ZEROOFF:
|
||||
@ -1503,7 +1934,7 @@ static int __init ns_init_module(void)
|
||||
{
|
||||
struct nand_chip *chip;
|
||||
struct nandsim *nand;
|
||||
int retval = -ENOMEM;
|
||||
int retval = -ENOMEM, i;
|
||||
|
||||
if (bus_width != 8 && bus_width != 16) {
|
||||
NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
|
||||
@ -1533,6 +1964,8 @@ static int __init ns_init_module(void)
|
||||
chip->verify_buf = ns_nand_verify_buf;
|
||||
chip->read_word = ns_nand_read_word;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
|
||||
/* and 'badblocks' parameters to work */
|
||||
chip->options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
/*
|
||||
@ -1557,6 +1990,15 @@ static int __init ns_init_module(void)
|
||||
|
||||
nsmtd->owner = THIS_MODULE;
|
||||
|
||||
if ((retval = parse_weakblocks()) != 0)
|
||||
goto error;
|
||||
|
||||
if ((retval = parse_weakpages()) != 0)
|
||||
goto error;
|
||||
|
||||
if ((retval = parse_gravepages()) != 0)
|
||||
goto error;
|
||||
|
||||
if ((retval = nand_scan(nsmtd, 1)) != 0) {
|
||||
NS_ERR("can't register NAND Simulator\n");
|
||||
if (retval > 0)
|
||||
@ -1564,23 +2006,44 @@ static int __init ns_init_module(void)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((retval = init_nandsim(nsmtd)) != 0) {
|
||||
NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
|
||||
goto error;
|
||||
if (overridesize) {
|
||||
u_int32_t new_size = nsmtd->erasesize << overridesize;
|
||||
if (new_size >> overridesize != nsmtd->erasesize) {
|
||||
NS_ERR("overridesize is too big\n");
|
||||
goto err_exit;
|
||||
}
|
||||
/* N.B. This relies on nand_scan not doing anything with the size before we change it */
|
||||
nsmtd->size = new_size;
|
||||
chip->chipsize = new_size;
|
||||
chip->chip_shift = ffs(new_size) - 1;
|
||||
}
|
||||
|
||||
if ((retval = nand_default_bbt(nsmtd)) != 0) {
|
||||
free_nandsim(nand);
|
||||
goto error;
|
||||
}
|
||||
if ((retval = setup_wear_reporting(nsmtd)) != 0)
|
||||
goto err_exit;
|
||||
|
||||
/* Register NAND as one big partition */
|
||||
add_mtd_partitions(nsmtd, &nand->part, 1);
|
||||
if ((retval = init_nandsim(nsmtd)) != 0)
|
||||
goto err_exit;
|
||||
|
||||
if ((retval = parse_badblocks(nand, nsmtd)) != 0)
|
||||
goto err_exit;
|
||||
|
||||
if ((retval = nand_default_bbt(nsmtd)) != 0)
|
||||
goto err_exit;
|
||||
|
||||
/* Register NAND partitions */
|
||||
if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0)
|
||||
goto err_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_exit:
|
||||
free_nandsim(nand);
|
||||
nand_release(nsmtd);
|
||||
for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
|
||||
kfree(nand->partitions[i].name);
|
||||
error:
|
||||
kfree(nsmtd);
|
||||
free_lists();
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -1593,10 +2056,14 @@ module_init(ns_init_module);
|
||||
static void __exit ns_cleanup_module(void)
|
||||
{
|
||||
struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv);
|
||||
int i;
|
||||
|
||||
free_nandsim(ns); /* Free nandsim private resources */
|
||||
nand_release(nsmtd); /* Unregisterd drived */
|
||||
nand_release(nsmtd); /* Unregister driver */
|
||||
for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
|
||||
kfree(ns->partitions[i].name);
|
||||
kfree(nsmtd); /* Free other structures */
|
||||
free_lists();
|
||||
}
|
||||
|
||||
module_exit(ns_cleanup_module);
|
||||
@ -1604,4 +2071,3 @@ module_exit(ns_cleanup_module);
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR ("Artem B. Bityuckiy");
|
||||
MODULE_DESCRIPTION ("The NAND flash simulator");
|
||||
|
||||
|
@ -2,20 +2,18 @@
|
||||
# linux/drivers/mtd/onenand/Kconfig
|
||||
#
|
||||
|
||||
menu "OneNAND Flash Device Drivers"
|
||||
depends on MTD != n
|
||||
|
||||
config MTD_ONENAND
|
||||
menuconfig MTD_ONENAND
|
||||
tristate "OneNAND Device Support"
|
||||
depends on MTD
|
||||
help
|
||||
This enables support for accessing all type of OneNAND flash
|
||||
devices. For further information see
|
||||
<http://www.samsung.com/Products/Semiconductor/Flash/OneNAND_TM/index.htm>.
|
||||
<http://www.samsung.com/Products/Semiconductor/OneNAND/index.htm>
|
||||
|
||||
if MTD_ONENAND
|
||||
|
||||
config MTD_ONENAND_VERIFY_WRITE
|
||||
bool "Verify OneNAND page writes"
|
||||
depends on MTD_ONENAND
|
||||
help
|
||||
This adds an extra check when data is written to the flash. The
|
||||
OneNAND flash device internally checks only bits transitioning
|
||||
@ -25,13 +23,12 @@ config MTD_ONENAND_VERIFY_WRITE
|
||||
|
||||
config MTD_ONENAND_GENERIC
|
||||
tristate "OneNAND Flash device via platform device driver"
|
||||
depends on MTD_ONENAND && ARM
|
||||
depends on ARM
|
||||
help
|
||||
Support for OneNAND flash via platform device driver.
|
||||
|
||||
config MTD_ONENAND_OTP
|
||||
bool "OneNAND OTP Support"
|
||||
depends on MTD_ONENAND
|
||||
help
|
||||
One Block of the NAND Flash Array memory is reserved as
|
||||
a One-Time Programmable Block memory area.
|
||||
@ -43,4 +40,4 @@ config MTD_ONENAND_OTP
|
||||
|
||||
OTP block is fully-guaranteed to be a valid block.
|
||||
|
||||
endmenu
|
||||
endif # MTD_ONENAND
|
||||
|
@ -836,9 +836,11 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
|
||||
int readcol = column;
|
||||
int readend = column + thislen;
|
||||
int lastgap = 0;
|
||||
unsigned int i;
|
||||
uint8_t *oob_buf = this->oob_buf;
|
||||
|
||||
for (free = this->ecclayout->oobfree; free->length; ++free) {
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
if (readcol >= lastgap)
|
||||
readcol += free->offset - lastgap;
|
||||
if (readend >= lastgap)
|
||||
@ -846,7 +848,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
|
||||
lastgap = free->offset + free->length;
|
||||
}
|
||||
this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
|
||||
for (free = this->ecclayout->oobfree; free->length; ++free) {
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
int free_end = free->offset + free->length;
|
||||
if (free->offset < readend && free_end > readcol) {
|
||||
int st = max_t(int,free->offset,readcol);
|
||||
@ -854,7 +857,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
|
||||
int n = ed - st;
|
||||
memcpy(buf, oob_buf + st, n);
|
||||
buf += n;
|
||||
} else
|
||||
} else if (column == 0)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@ -1280,15 +1283,18 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
|
||||
int writecol = column;
|
||||
int writeend = column + thislen;
|
||||
int lastgap = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (free = this->ecclayout->oobfree; free->length; ++free) {
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
if (writecol >= lastgap)
|
||||
writecol += free->offset - lastgap;
|
||||
if (writeend >= lastgap)
|
||||
writeend += free->offset - lastgap;
|
||||
lastgap = free->offset + free->length;
|
||||
}
|
||||
for (free = this->ecclayout->oobfree; free->length; ++free) {
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
int free_end = free->offset + free->length;
|
||||
if (free->offset < writeend && free_end > writecol) {
|
||||
int st = max_t(int,free->offset,writecol);
|
||||
@ -1296,7 +1302,7 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
|
||||
int n = ed - st;
|
||||
memcpy(oob_buf + st, buf, n);
|
||||
buf += n;
|
||||
} else
|
||||
} else if (column == 0)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@ -2386,7 +2392,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
|
||||
* the out of band area
|
||||
*/
|
||||
this->ecclayout->oobavail = 0;
|
||||
for (i = 0; this->ecclayout->oobfree[i].length; i++)
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
|
||||
this->ecclayout->oobfree[i].length; i++)
|
||||
this->ecclayout->oobavail +=
|
||||
this->ecclayout->oobfree[i].length;
|
||||
mtd->oobavail = this->ecclayout->oobavail;
|
||||
|
@ -1,7 +1,7 @@
|
||||
The files in this directory and elsewhere which refer to this LICENCE
|
||||
file are part of JFFS2, the Journalling Flash File System v2.
|
||||
|
||||
Copyright (C) 2001, 2002 Red Hat, Inc.
|
||||
Copyright © 2001-2007 Red Hat, Inc. and others
|
||||
|
||||
JFFS2 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
|
||||
@ -28,8 +28,3 @@ of the GNU General Public License.
|
||||
This exception does not invalidate any other reasons why a work based on
|
||||
this file might be covered by the GNU General Public License.
|
||||
|
||||
For information on obtaining alternative licences for JFFS2, see
|
||||
http://sources.redhat.com/jffs2/jffs2-licence.html
|
||||
|
||||
|
||||
$Id: LICENCE,v 1.1 2002/05/20 14:56:37 dwmw2 Exp $
|
||||
|
@ -1,7 +1,6 @@
|
||||
#
|
||||
# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
|
||||
#
|
||||
# $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $
|
||||
#
|
||||
|
||||
obj-$(CONFIG_JFFS2_FS) += jffs2.o
|
||||
|
@ -1,4 +1,3 @@
|
||||
$Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $
|
||||
|
||||
JFFS2 LOCKING DOCUMENTATION
|
||||
---------------------------
|
||||
|
@ -1,4 +1,3 @@
|
||||
$Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $
|
||||
|
||||
- support asynchronous operation -- add a per-fs 'reserved_space' count,
|
||||
let each outstanding write reserve the _maximum_ amount of physical
|
||||
@ -30,8 +29,6 @@ $Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $
|
||||
the full dirent, we only need to go to the flash in lookup() when we think we've
|
||||
got a match, and in readdir().
|
||||
- Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately?
|
||||
- Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
|
||||
jffs2_mark_node_obsolete(). Can all callers work it out?
|
||||
- Remove size from jffs2_raw_node_frag.
|
||||
|
||||
dedekind:
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
* Copyright © 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
* Copyright © 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
struct jffs2_acl_entry {
|
||||
jint16_t e_tag;
|
||||
jint16_t e_perm;
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: build.c,v 1.85 2005/11/07 11:14:38 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
144
fs/jffs2/compr.c
144
fs/jffs2/compr.c
@ -1,16 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
* Created by Arjan van de Ven <arjanv@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "compr.h"
|
||||
@ -268,144 +266,6 @@ int jffs2_unregister_compressor(struct jffs2_compressor *comp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JFFS2_PROC
|
||||
|
||||
#define JFFS2_STAT_BUF_SIZE 16000
|
||||
|
||||
char *jffs2_list_compressors(void)
|
||||
{
|
||||
struct jffs2_compressor *this;
|
||||
char *buf, *act_buf;
|
||||
|
||||
act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
|
||||
list_for_each_entry(this, &jffs2_compressor_list, list) {
|
||||
act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
|
||||
if ((this->disabled)||(!this->compress))
|
||||
act_buf += sprintf(act_buf,"disabled");
|
||||
else
|
||||
act_buf += sprintf(act_buf,"enabled");
|
||||
act_buf += sprintf(act_buf,"\n");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *jffs2_stats(void)
|
||||
{
|
||||
struct jffs2_compressor *this;
|
||||
char *buf, *act_buf;
|
||||
|
||||
act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
|
||||
|
||||
act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
|
||||
act_buf += sprintf(act_buf,"%10s ","none");
|
||||
act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks,
|
||||
none_stat_compr_size, none_stat_decompr_blocks);
|
||||
spin_lock(&jffs2_compressor_list_lock);
|
||||
list_for_each_entry(this, &jffs2_compressor_list, list) {
|
||||
act_buf += sprintf(act_buf,"%10s ",this->name);
|
||||
if ((this->disabled)||(!this->compress))
|
||||
act_buf += sprintf(act_buf,"- ");
|
||||
else
|
||||
act_buf += sprintf(act_buf,"+ ");
|
||||
act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks,
|
||||
this->stat_compr_new_size, this->stat_compr_orig_size,
|
||||
this->stat_decompr_blocks);
|
||||
act_buf += sprintf(act_buf,"\n");
|
||||
}
|
||||
spin_unlock(&jffs2_compressor_list_lock);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *jffs2_get_compression_mode_name(void)
|
||||
{
|
||||
switch (jffs2_compression_mode) {
|
||||
case JFFS2_COMPR_MODE_NONE:
|
||||
return "none";
|
||||
case JFFS2_COMPR_MODE_PRIORITY:
|
||||
return "priority";
|
||||
case JFFS2_COMPR_MODE_SIZE:
|
||||
return "size";
|
||||
}
|
||||
return "unkown";
|
||||
}
|
||||
|
||||
int jffs2_set_compression_mode_name(const char *name)
|
||||
{
|
||||
if (!strcmp("none",name)) {
|
||||
jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp("priority",name)) {
|
||||
jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp("size",name)) {
|
||||
jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int jffs2_compressor_Xable(const char *name, int disabled)
|
||||
{
|
||||
struct jffs2_compressor *this;
|
||||
spin_lock(&jffs2_compressor_list_lock);
|
||||
list_for_each_entry(this, &jffs2_compressor_list, list) {
|
||||
if (!strcmp(this->name, name)) {
|
||||
this->disabled = disabled;
|
||||
spin_unlock(&jffs2_compressor_list_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spin_unlock(&jffs2_compressor_list_lock);
|
||||
printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int jffs2_enable_compressor_name(const char *name)
|
||||
{
|
||||
return jffs2_compressor_Xable(name, 0);
|
||||
}
|
||||
|
||||
int jffs2_disable_compressor_name(const char *name)
|
||||
{
|
||||
return jffs2_compressor_Xable(name, 1);
|
||||
}
|
||||
|
||||
int jffs2_set_compressor_priority(const char *name, int priority)
|
||||
{
|
||||
struct jffs2_compressor *this,*comp;
|
||||
spin_lock(&jffs2_compressor_list_lock);
|
||||
list_for_each_entry(this, &jffs2_compressor_list, list) {
|
||||
if (!strcmp(this->name, name)) {
|
||||
this->priority = priority;
|
||||
comp = this;
|
||||
goto reinsert;
|
||||
}
|
||||
}
|
||||
spin_unlock(&jffs2_compressor_list_lock);
|
||||
printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
|
||||
return 1;
|
||||
reinsert:
|
||||
/* list is sorted in the order of priority, so if
|
||||
we change it we have to reinsert it into the
|
||||
good place */
|
||||
list_del(&comp->list);
|
||||
list_for_each_entry(this, &jffs2_compressor_list, list) {
|
||||
if (this->priority < comp->priority) {
|
||||
list_add(&comp->list, this->list.prev);
|
||||
spin_unlock(&jffs2_compressor_list_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
list_add_tail(&comp->list, &jffs2_compressor_list);
|
||||
spin_unlock(&jffs2_compressor_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
|
||||
{
|
||||
if (orig != comprbuf)
|
||||
|
@ -1,13 +1,10 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in the
|
||||
* jffs2 directory.
|
||||
*
|
||||
* $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -76,16 +73,6 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||
|
||||
void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
|
||||
|
||||
#ifdef CONFIG_JFFS2_PROC
|
||||
int jffs2_enable_compressor_name(const char *name);
|
||||
int jffs2_disable_compressor_name(const char *name);
|
||||
int jffs2_set_compression_mode_name(const char *mode_name);
|
||||
char *jffs2_get_compression_mode_name(void);
|
||||
int jffs2_set_compressor_priority(const char *mode_name, int priority);
|
||||
char *jffs2_list_compressors(void);
|
||||
char *jffs2_stats(void);
|
||||
#endif
|
||||
|
||||
/* Compressor modules */
|
||||
/* These functions will be called by jffs2_compressors_init/exit */
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by Arjan van de Ven <arjanv@redhat.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $
|
||||
*
|
||||
*
|
||||
* Very simple lz77-ish encoder.
|
||||
|
@ -1,23 +1,94 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by Arjan van de Ven <arjanv@redhat.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/jffs2.h>
|
||||
#include "compr_rubin.h"
|
||||
#include "histo_mips.h"
|
||||
#include <linux/errno.h>
|
||||
#include "compr.h"
|
||||
|
||||
|
||||
#define RUBIN_REG_SIZE 16
|
||||
#define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1))
|
||||
#define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1)
|
||||
|
||||
|
||||
#define BIT_DIVIDER_MIPS 1043
|
||||
static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
struct pushpull {
|
||||
unsigned char *buf;
|
||||
unsigned int buflen;
|
||||
unsigned int ofs;
|
||||
unsigned int reserve;
|
||||
};
|
||||
|
||||
struct rubin_state {
|
||||
unsigned long p;
|
||||
unsigned long q;
|
||||
unsigned long rec_q;
|
||||
long bit_number;
|
||||
struct pushpull pp;
|
||||
int bit_divider;
|
||||
int bits[8];
|
||||
};
|
||||
|
||||
static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve)
|
||||
{
|
||||
pp->buf = buf;
|
||||
pp->buflen = buflen;
|
||||
pp->ofs = ofs;
|
||||
pp->reserve = reserve;
|
||||
}
|
||||
|
||||
static inline int pushbit(struct pushpull *pp, int bit, int use_reserved)
|
||||
{
|
||||
if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (bit) {
|
||||
pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7)));
|
||||
}
|
||||
else {
|
||||
pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7)));
|
||||
}
|
||||
pp->ofs++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pushedbits(struct pushpull *pp)
|
||||
{
|
||||
return pp->ofs;
|
||||
}
|
||||
|
||||
static inline int pullbit(struct pushpull *pp)
|
||||
{
|
||||
int bit;
|
||||
|
||||
bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1;
|
||||
|
||||
pp->ofs++;
|
||||
return bit;
|
||||
}
|
||||
|
||||
static inline int pulledbits(struct pushpull *pp)
|
||||
{
|
||||
return pp->ofs;
|
||||
}
|
||||
|
||||
|
||||
static void init_rubin(struct rubin_state *rs, int div, int *bits)
|
||||
{
|
||||
int c;
|
||||
|
@ -1,21 +0,0 @@
|
||||
/* Rubin encoder/decoder header */
|
||||
/* work started at : aug 3, 1994 */
|
||||
/* last modification : aug 15, 1994 */
|
||||
/* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */
|
||||
|
||||
#include "pushpull.h"
|
||||
|
||||
#define RUBIN_REG_SIZE 16
|
||||
#define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1))
|
||||
#define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1)
|
||||
|
||||
|
||||
struct rubin_state {
|
||||
unsigned long p;
|
||||
unsigned long q;
|
||||
unsigned long rec_q;
|
||||
long bit_number;
|
||||
struct pushpull pp;
|
||||
int bit_divider;
|
||||
int bits[8];
|
||||
};
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(__KERNEL__) && !defined(__ECOS)
|
||||
|
@ -1,307 +0,0 @@
|
||||
/* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/types.h>
|
||||
#if 0
|
||||
#define TESTDATA_LEN 512
|
||||
static unsigned char testdata[TESTDATA_LEN] = {
|
||||
0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00,
|
||||
0xb0, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x06, 0x00, 0x28, 0x00,
|
||||
0x1e, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x80, 0x04, 0x08,
|
||||
0x34, 0x80, 0x04, 0x08, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x80, 0x04, 0x08,
|
||||
0xf4, 0x80, 0x04, 0x08, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08,
|
||||
0x00, 0x80, 0x04, 0x08, 0x0d, 0x05, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x95, 0x04, 0x08,
|
||||
0x10, 0x95, 0x04, 0x08, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x58, 0x95, 0x04, 0x08,
|
||||
0x58, 0x95, 0x04, 0x08, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x81, 0x04, 0x08,
|
||||
0x08, 0x81, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x75,
|
||||
0x78, 0x2e, 0x73, 0x6f, 0x2e, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x83, 0x04, 0x08, 0x81, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x83, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
|
||||
0x2c, 0x83, 0x04, 0x08, 0xdd, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x3c, 0x83, 0x04, 0x08, 0x2e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x4c, 0x83, 0x04, 0x08, 0x7d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
|
||||
0x00, 0x85, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x67,
|
||||
0x6d, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x5f, 0x00, 0x6c, 0x69, 0x62, 0x63,
|
||||
0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x5f, 0x5f, 0x63};
|
||||
#else
|
||||
#define TESTDATA_LEN 3481
|
||||
static unsigned char testdata[TESTDATA_LEN] = {
|
||||
0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x22, 0x64, 0x62, 0x65, 0x6e, 0x63, 0x68,
|
||||
0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4d, 0x41, 0x58,
|
||||
0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x31, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x73, 0x74, 0x61,
|
||||
0x74, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x62, 0x75, 0x66, 0x5b, 0x37, 0x30, 0x30,
|
||||
0x30, 0x30, 0x5d, 0x3b, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x20,
|
||||
0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x61,
|
||||
0x74, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x09, 0x69, 0x6e,
|
||||
0x74, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c,
|
||||
0x65, 0x3b, 0x0a, 0x7d, 0x20, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x4d, 0x41, 0x58, 0x5f,
|
||||
0x46, 0x49, 0x4c, 0x45, 0x53, 0x5d, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f,
|
||||
0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72,
|
||||
0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x75,
|
||||
0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20,
|
||||
0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28,
|
||||
0x25, 0x64, 0x29, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61,
|
||||
0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09,
|
||||
0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a,
|
||||
0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20,
|
||||
0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x3b, 0x0a,
|
||||
0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a,
|
||||
0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x49, 0x4e, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x6f, 0x66,
|
||||
0x28, 0x62, 0x75, 0x66, 0x29, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09,
|
||||
0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73,
|
||||
0x29, 0x3b, 0x0a, 0x09, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x3d, 0x20, 0x73, 0x3b, 0x0a,
|
||||
0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6f, 0x70,
|
||||
0x65, 0x6e, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20,
|
||||
0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20,
|
||||
0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c,
|
||||
0x20, 0x69, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d,
|
||||
0x20, 0x4f, 0x5f, 0x52, 0x44, 0x57, 0x52, 0x7c, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x3b,
|
||||
0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74,
|
||||
0x3b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28,
|
||||
0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69,
|
||||
0x7a, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x7c,
|
||||
0x3d, 0x20, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x64, 0x20,
|
||||
0x3d, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x6c,
|
||||
0x61, 0x67, 0x73, 0x2c, 0x20, 0x30, 0x36, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20,
|
||||
0x28, 0x66, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70,
|
||||
0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x6f, 0x70, 0x65, 0x6e,
|
||||
0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68,
|
||||
0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22,
|
||||
0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65,
|
||||
0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x68,
|
||||
0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28,
|
||||
0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
|
||||
0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x64, 0x2c,
|
||||
0x20, 0x26, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65,
|
||||
0x20, 0x3e, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b,
|
||||
0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
|
||||
0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64,
|
||||
0x69, 0x6e, 0x67, 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f,
|
||||
0x6d, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74,
|
||||
0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x23, 0x65,
|
||||
0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69,
|
||||
0x6c, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x74,
|
||||
0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x20, 0x65, 0x6c,
|
||||
0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3c, 0x20, 0x73, 0x74,
|
||||
0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72,
|
||||
0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67,
|
||||
0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x25,
|
||||
0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e,
|
||||
0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09,
|
||||
0x09, 0x66, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69,
|
||||
0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69,
|
||||
0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20,
|
||||
0x30, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66,
|
||||
0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53,
|
||||
0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x66, 0x69,
|
||||
0x6c, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x66, 0x6f,
|
||||
0x72, 0x20, 0x25, 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b,
|
||||
0x0a, 0x09, 0x09, 0x65, 0x78, 0x69, 0x74, 0x28, 0x31, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09,
|
||||
0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65,
|
||||
0x20, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09,
|
||||
0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x20, 0x25, 0x20, 0x31, 0x30,
|
||||
0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e,
|
||||
0x74, 0x66, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76,
|
||||
0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x69, 0x6e, 0x74,
|
||||
0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a,
|
||||
0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x0a, 0x7b,
|
||||
0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x62,
|
||||
0x75, 0x66, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x6d, 0x65, 0x6d, 0x73,
|
||||
0x65, 0x74, 0x28, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x6f,
|
||||
0x66, 0x28, 0x62, 0x75, 0x66, 0x29, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28,
|
||||
0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b,
|
||||
0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d,
|
||||
0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a,
|
||||
0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58,
|
||||
0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x31, 0x0a,
|
||||
0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64,
|
||||
0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20,
|
||||
0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20,
|
||||
0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e,
|
||||
0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e,
|
||||
0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c,
|
||||
0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a,
|
||||
0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b,
|
||||
0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c,
|
||||
0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20,
|
||||
0x28, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d,
|
||||
0x2e, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20,
|
||||
0x21, 0x3d, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
|
||||
0x6e, 0x74, 0x66, 0x28, 0x22, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65,
|
||||
0x64, 0x20, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x5c, 0x6e,
|
||||
0x22, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d,
|
||||
0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x28, 0x69,
|
||||
0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29,
|
||||
0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20,
|
||||
0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53,
|
||||
0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d,
|
||||
0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b,
|
||||
0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41,
|
||||
0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
|
||||
0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61,
|
||||
0x64, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73,
|
||||
0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25,
|
||||
0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c,
|
||||
0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75,
|
||||
0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73,
|
||||
0x65, 0x74, 0x2c, 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09,
|
||||
0x72, 0x65, 0x61, 0x64, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66,
|
||||
0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x7d,
|
||||
0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28,
|
||||
0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69,
|
||||
0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b,
|
||||
0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29,
|
||||
0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b,
|
||||
0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e,
|
||||
0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09,
|
||||
0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c,
|
||||
0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22,
|
||||
0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x3a, 0x20, 0x68,
|
||||
0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74,
|
||||
0x20, 0x6f, 0x70, 0x65, 0x6e, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20,
|
||||
0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
|
||||
0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x66, 0x74, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x29, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20,
|
||||
0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6d, 0x6b,
|
||||
0x64, 0x69, 0x72, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29,
|
||||
0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6d, 0x6b, 0x64, 0x69, 0x72,
|
||||
0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x30, 0x37, 0x30, 0x30, 0x29, 0x20, 0x21, 0x3d,
|
||||
0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a,
|
||||
0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20,
|
||||
0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e,
|
||||
0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72,
|
||||
0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x7d, 0x0a,
|
||||
0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x6d, 0x64, 0x69, 0x72,
|
||||
0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a,
|
||||
0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29,
|
||||
0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x28, 0x66, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70,
|
||||
0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x25, 0x73, 0x20,
|
||||
0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20,
|
||||
0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
|
||||
0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29,
|
||||
0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f,
|
||||
0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6f, 0x6c,
|
||||
0x64, 0x2c, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6e, 0x65, 0x77, 0x29, 0x0a, 0x7b, 0x0a,
|
||||
0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6f, 0x6c, 0x64, 0x29, 0x3b, 0x0a,
|
||||
0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6e, 0x65, 0x77, 0x29, 0x3b, 0x0a,
|
||||
0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6f, 0x6c, 0x64,
|
||||
0x2c, 0x20, 0x6e, 0x65, 0x77, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09,
|
||||
0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20,
|
||||
0x25, 0x73, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73,
|
||||
0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72,
|
||||
0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d,
|
||||
0x0a, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x28,
|
||||
0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74,
|
||||
0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
|
||||
0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75,
|
||||
0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69,
|
||||
0x66, 0x20, 0x28, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x26,
|
||||
0x73, 0x74, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72,
|
||||
0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74,
|
||||
0x61, 0x74, 0x3a, 0x20, 0x25, 0x73, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x25,
|
||||
0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74,
|
||||
0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x53, 0x5f, 0x49,
|
||||
0x53, 0x44, 0x49, 0x52, 0x28, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x29,
|
||||
0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28,
|
||||
0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x73, 0x69,
|
||||
0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22,
|
||||
0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73,
|
||||
0x20, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x25, 0x64, 0x20, 0x25,
|
||||
0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69,
|
||||
0x7a, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a,
|
||||
0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28,
|
||||
0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74,
|
||||
0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x6f, 0x70, 0x65,
|
||||
0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x35, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28,
|
||||
0x35, 0x30, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x0a
|
||||
};
|
||||
#endif
|
||||
static unsigned char comprbuf[TESTDATA_LEN];
|
||||
static unsigned char decomprbuf[TESTDATA_LEN];
|
||||
|
||||
int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
|
||||
unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
|
||||
unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
uint32_t *datalen, uint32_t *cdatalen);
|
||||
|
||||
int init_module(void ) {
|
||||
unsigned char comprtype;
|
||||
uint32_t c, d;
|
||||
int ret;
|
||||
|
||||
printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
testdata[0],testdata[1],testdata[2],testdata[3],
|
||||
testdata[4],testdata[5],testdata[6],testdata[7],
|
||||
testdata[8],testdata[9],testdata[10],testdata[11],
|
||||
testdata[12],testdata[13],testdata[14],testdata[15]);
|
||||
d = TESTDATA_LEN;
|
||||
c = TESTDATA_LEN;
|
||||
comprtype = jffs2_compress(testdata, comprbuf, &d, &c);
|
||||
|
||||
printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n",
|
||||
comprtype, c, d);
|
||||
printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3],
|
||||
comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7],
|
||||
comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11],
|
||||
comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]);
|
||||
|
||||
ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d);
|
||||
printk("jffs2_decompress returned %d\n", ret);
|
||||
printk("Decompressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3],
|
||||
decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7],
|
||||
decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11],
|
||||
decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]);
|
||||
if (memcmp(decomprbuf, testdata, d))
|
||||
printk("Compression and decompression corrupted data\n");
|
||||
else
|
||||
printk("Compression good for %d bytes\n", d);
|
||||
return 1;
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
@ -1,15 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: debug.h,v 1.21 2005/11/07 11:14:39 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JFFS2_DEBUG_H_
|
||||
#define _JFFS2_DEBUG_H_
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -333,7 +331,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
|
||||
|
||||
*bad_offset = ofs;
|
||||
|
||||
ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
|
||||
ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
|
||||
goto fail;
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: fs.c,v 1.66 2005/09/27 13:17:29 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -144,7 +142,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
c->unchecked_size);
|
||||
jffs2_dbg_dump_block_lists_nolock(c);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
BUG();
|
||||
up(&c->alloc_sem);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: ioctl.c,v 1.10 2005/11/07 11:14:40 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
@ -1,4 +1,13 @@
|
||||
/* $Id: jffs2_fs_i.h,v 1.19 2005/11/07 11:14:52 gleixner Exp $ */
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JFFS2_FS_I
|
||||
#define _JFFS2_FS_I
|
||||
|
@ -1,4 +1,13 @@
|
||||
/* $Id: jffs2_fs_sb.h,v 1.54 2005/09/21 13:37:34 dedekind Exp $ */
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JFFS2_FS_SB
|
||||
#define _JFFS2_FS_SB
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: nodelist.c,v 1.115 2005/11/07 11:14:40 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -54,7 +52,7 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
|
||||
*prev = new;
|
||||
}
|
||||
|
||||
void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
|
||||
uint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
|
||||
{
|
||||
struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
|
||||
|
||||
@ -76,18 +74,24 @@ void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the last fragment starts at the RAM page boundary, it is
|
||||
* REF_PRISTINE irrespective of its size.
|
||||
*/
|
||||
frag = frag_last(list);
|
||||
|
||||
/* Sanity check for truncation to longer than we started with... */
|
||||
if (!frag)
|
||||
return 0;
|
||||
if (frag->ofs + frag->size < size)
|
||||
return frag->ofs + frag->size;
|
||||
|
||||
/* If the last fragment starts at the RAM page boundary, it is
|
||||
* REF_PRISTINE irrespective of its size. */
|
||||
if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) {
|
||||
dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n",
|
||||
frag->ofs, frag->ofs + frag->size);
|
||||
frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
|
||||
@ -397,466 +401,6 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the data CRC of the node.
|
||||
*
|
||||
* Returns: 0 if the data CRC is correct;
|
||||
* 1 - if incorrect;
|
||||
* error code if an error occured.
|
||||
*/
|
||||
static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
|
||||
{
|
||||
struct jffs2_raw_node_ref *ref = tn->fn->raw;
|
||||
int err = 0, pointed = 0;
|
||||
struct jffs2_eraseblock *jeb;
|
||||
unsigned char *buffer;
|
||||
uint32_t crc, ofs, len;
|
||||
size_t retlen;
|
||||
|
||||
BUG_ON(tn->csize == 0);
|
||||
|
||||
if (!jffs2_is_writebuffered(c))
|
||||
goto adj_acc;
|
||||
|
||||
/* Calculate how many bytes were already checked */
|
||||
ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
|
||||
len = ofs % c->wbuf_pagesize;
|
||||
if (likely(len))
|
||||
len = c->wbuf_pagesize - len;
|
||||
|
||||
if (len >= tn->csize) {
|
||||
dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
|
||||
ref_offset(ref), tn->csize, ofs);
|
||||
goto adj_acc;
|
||||
}
|
||||
|
||||
ofs += len;
|
||||
len = tn->csize - len;
|
||||
|
||||
dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
|
||||
ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
|
||||
|
||||
#ifndef __ECOS
|
||||
/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
|
||||
* adding and jffs2_flash_read_end() interface. */
|
||||
if (c->mtd->point) {
|
||||
err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
|
||||
if (!err && retlen < tn->csize) {
|
||||
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
|
||||
c->mtd->unpoint(c->mtd, buffer, ofs, len);
|
||||
} else if (err)
|
||||
JFFS2_WARNING("MTD point failed: error code %d.\n", err);
|
||||
else
|
||||
pointed = 1; /* succefully pointed to device */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!pointed) {
|
||||
buffer = kmalloc(len, GFP_KERNEL);
|
||||
if (unlikely(!buffer))
|
||||
return -ENOMEM;
|
||||
|
||||
/* TODO: this is very frequent pattern, make it a separate
|
||||
* routine */
|
||||
err = jffs2_flash_read(c, ofs, len, &retlen, buffer);
|
||||
if (err) {
|
||||
JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err);
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
if (retlen != len) {
|
||||
JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len);
|
||||
err = -EIO;
|
||||
goto free_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Continue calculating CRC */
|
||||
crc = crc32(tn->partial_crc, buffer, len);
|
||||
if(!pointed)
|
||||
kfree(buffer);
|
||||
#ifndef __ECOS
|
||||
else
|
||||
c->mtd->unpoint(c->mtd, buffer, ofs, len);
|
||||
#endif
|
||||
|
||||
if (crc != tn->data_crc) {
|
||||
JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
|
||||
ofs, tn->data_crc, crc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
adj_acc:
|
||||
jeb = &c->blocks[ref->flash_offset / c->sector_size];
|
||||
len = ref_totlen(c, jeb, ref);
|
||||
|
||||
/*
|
||||
* Mark the node as having been checked and fix the
|
||||
* accounting accordingly.
|
||||
*/
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
jeb->used_size += len;
|
||||
jeb->unchecked_size -= len;
|
||||
c->used_size += len;
|
||||
c->unchecked_size -= len;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
free_out:
|
||||
if(!pointed)
|
||||
kfree(buffer);
|
||||
#ifndef __ECOS
|
||||
else
|
||||
c->mtd->unpoint(c->mtd, buffer, ofs, len);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for jffs2_add_older_frag_to_fragtree().
|
||||
*
|
||||
* Checks the node if we are in the checking stage.
|
||||
*/
|
||||
static int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(ref_obsolete(tn->fn->raw));
|
||||
|
||||
/* We only check the data CRC of unchecked nodes */
|
||||
if (ref_flags(tn->fn->raw) != REF_UNCHECKED)
|
||||
return 0;
|
||||
|
||||
dbg_fragtree2("check node %#04x-%#04x, phys offs %#08x.\n",
|
||||
tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw));
|
||||
|
||||
ret = check_node_data(c, tn);
|
||||
if (unlikely(ret < 0)) {
|
||||
JFFS2_ERROR("check_node_data() returned error: %d.\n",
|
||||
ret);
|
||||
} else if (unlikely(ret > 0)) {
|
||||
dbg_fragtree2("CRC error, mark it obsolete.\n");
|
||||
jffs2_mark_node_obsolete(c, tn->fn->raw);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for jffs2_add_older_frag_to_fragtree().
|
||||
*
|
||||
* Called when the new fragment that is being inserted
|
||||
* splits a hole fragment.
|
||||
*/
|
||||
static int split_hole(struct jffs2_sb_info *c, struct rb_root *root,
|
||||
struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole)
|
||||
{
|
||||
dbg_fragtree2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n",
|
||||
newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size);
|
||||
|
||||
if (hole->ofs == newfrag->ofs) {
|
||||
/*
|
||||
* Well, the new fragment actually starts at the same offset as
|
||||
* the hole.
|
||||
*/
|
||||
if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
|
||||
/*
|
||||
* We replace the overlapped left part of the hole by
|
||||
* the new node.
|
||||
*/
|
||||
|
||||
dbg_fragtree2("insert fragment %#04x-%#04x and cut the left part of the hole\n",
|
||||
newfrag->ofs, newfrag->ofs + newfrag->size);
|
||||
rb_replace_node(&hole->rb, &newfrag->rb, root);
|
||||
|
||||
hole->ofs += newfrag->size;
|
||||
hole->size -= newfrag->size;
|
||||
|
||||
/*
|
||||
* We know that 'hole' should be the right hand
|
||||
* fragment.
|
||||
*/
|
||||
jffs2_fragtree_insert(hole, newfrag);
|
||||
rb_insert_color(&hole->rb, root);
|
||||
} else {
|
||||
/*
|
||||
* Ah, the new fragment is of the same size as the hole.
|
||||
* Relace the hole by it.
|
||||
*/
|
||||
dbg_fragtree2("insert fragment %#04x-%#04x and overwrite hole\n",
|
||||
newfrag->ofs, newfrag->ofs + newfrag->size);
|
||||
rb_replace_node(&hole->rb, &newfrag->rb, root);
|
||||
jffs2_free_node_frag(hole);
|
||||
}
|
||||
} else {
|
||||
/* The new fragment lefts some hole space at the left */
|
||||
|
||||
struct jffs2_node_frag * newfrag2 = NULL;
|
||||
|
||||
if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
|
||||
/* The new frag also lefts some space at the right */
|
||||
newfrag2 = new_fragment(NULL, newfrag->ofs +
|
||||
newfrag->size, hole->ofs + hole->size
|
||||
- newfrag->ofs - newfrag->size);
|
||||
if (unlikely(!newfrag2)) {
|
||||
jffs2_free_node_frag(newfrag);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
hole->size = newfrag->ofs - hole->ofs;
|
||||
dbg_fragtree2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n",
|
||||
hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size);
|
||||
|
||||
jffs2_fragtree_insert(newfrag, hole);
|
||||
rb_insert_color(&newfrag->rb, root);
|
||||
|
||||
if (newfrag2) {
|
||||
dbg_fragtree2("left the hole %#04x-%#04x at the right\n",
|
||||
newfrag2->ofs, newfrag2->ofs + newfrag2->size);
|
||||
jffs2_fragtree_insert(newfrag2, newfrag);
|
||||
rb_insert_color(&newfrag2->rb, root);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used when we build inode. It expects the nodes are passed
|
||||
* in the decreasing version order. The whole point of this is to improve the
|
||||
* inodes checking on NAND: we check the nodes' data CRC only when they are not
|
||||
* obsoleted. Previously, add_frag_to_fragtree() function was used and
|
||||
* nodes were passed to it in the increasing version ordes and CRCs of all
|
||||
* nodes were checked.
|
||||
*
|
||||
* Note: tn->fn->size shouldn't be zero.
|
||||
*
|
||||
* Returns 0 if the node was inserted
|
||||
* 1 if it wasn't inserted (since it is obsolete)
|
||||
* < 0 an if error occured
|
||||
*/
|
||||
int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||
struct jffs2_tmp_dnode_info *tn)
|
||||
{
|
||||
struct jffs2_node_frag *this, *newfrag;
|
||||
uint32_t lastend;
|
||||
struct jffs2_full_dnode *fn = tn->fn;
|
||||
struct rb_root *root = &f->fragtree;
|
||||
uint32_t fn_size = fn->size, fn_ofs = fn->ofs;
|
||||
int err, checked = 0;
|
||||
int ref_flag;
|
||||
|
||||
dbg_fragtree("insert fragment %#04x-%#04x, ver %u\n", fn_ofs, fn_ofs + fn_size, tn->version);
|
||||
|
||||
/* Skip all the nodes which are completed before this one starts */
|
||||
this = jffs2_lookup_node_frag(root, fn_ofs);
|
||||
if (this)
|
||||
dbg_fragtree2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole");
|
||||
|
||||
if (this)
|
||||
lastend = this->ofs + this->size;
|
||||
else
|
||||
lastend = 0;
|
||||
|
||||
/* Detect the preliminary type of node */
|
||||
if (fn->size >= PAGE_CACHE_SIZE)
|
||||
ref_flag = REF_PRISTINE;
|
||||
else
|
||||
ref_flag = REF_NORMAL;
|
||||
|
||||
/* See if we ran off the end of the root */
|
||||
if (lastend <= fn_ofs) {
|
||||
/* We did */
|
||||
|
||||
/*
|
||||
* We are going to insert the new node into the
|
||||
* fragment tree, so check it.
|
||||
*/
|
||||
err = check_node(c, f, tn);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
fn->frags = 1;
|
||||
|
||||
newfrag = new_fragment(fn, fn_ofs, fn_size);
|
||||
if (unlikely(!newfrag))
|
||||
return -ENOMEM;
|
||||
|
||||
err = no_overlapping_node(c, root, newfrag, this, lastend);
|
||||
if (unlikely(err != 0)) {
|
||||
jffs2_free_node_frag(newfrag);
|
||||
return err;
|
||||
}
|
||||
|
||||
goto out_ok;
|
||||
}
|
||||
|
||||
fn->frags = 0;
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Here we have:
|
||||
* fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs.
|
||||
*
|
||||
* Remember, 'this' has higher version, any non-hole node
|
||||
* which is already in the fragtree is newer then the newly
|
||||
* inserted.
|
||||
*/
|
||||
if (!this->node) {
|
||||
/*
|
||||
* 'this' is the hole fragment, so at least the
|
||||
* beginning of the new fragment is valid.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We are going to insert the new node into the
|
||||
* fragment tree, so check it.
|
||||
*/
|
||||
if (!checked) {
|
||||
err = check_node(c, f, tn);
|
||||
if (unlikely(err != 0))
|
||||
return err;
|
||||
checked = 1;
|
||||
}
|
||||
|
||||
if (this->ofs + this->size >= fn_ofs + fn_size) {
|
||||
/* We split the hole on two parts */
|
||||
|
||||
fn->frags += 1;
|
||||
newfrag = new_fragment(fn, fn_ofs, fn_size);
|
||||
if (unlikely(!newfrag))
|
||||
return -ENOMEM;
|
||||
|
||||
err = split_hole(c, root, newfrag, this);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
goto out_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* The beginning of the new fragment is valid since it
|
||||
* overlaps the hole node.
|
||||
*/
|
||||
|
||||
ref_flag = REF_NORMAL;
|
||||
|
||||
fn->frags += 1;
|
||||
newfrag = new_fragment(fn, fn_ofs,
|
||||
this->ofs + this->size - fn_ofs);
|
||||
if (unlikely(!newfrag))
|
||||
return -ENOMEM;
|
||||
|
||||
if (fn_ofs == this->ofs) {
|
||||
/*
|
||||
* The new node starts at the same offset as
|
||||
* the hole and supersieds the hole.
|
||||
*/
|
||||
dbg_fragtree2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n",
|
||||
fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
|
||||
|
||||
rb_replace_node(&this->rb, &newfrag->rb, root);
|
||||
jffs2_free_node_frag(this);
|
||||
} else {
|
||||
/*
|
||||
* The hole becomes shorter as its right part
|
||||
* is supersieded by the new fragment.
|
||||
*/
|
||||
dbg_fragtree2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n",
|
||||
this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size);
|
||||
|
||||
dbg_fragtree2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs,
|
||||
fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
|
||||
|
||||
this->size -= newfrag->size;
|
||||
jffs2_fragtree_insert(newfrag, this);
|
||||
rb_insert_color(&newfrag->rb, root);
|
||||
}
|
||||
|
||||
fn_ofs += newfrag->size;
|
||||
fn_size -= newfrag->size;
|
||||
this = rb_entry(rb_next(&newfrag->rb),
|
||||
struct jffs2_node_frag, rb);
|
||||
|
||||
dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
|
||||
this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
|
||||
}
|
||||
|
||||
/*
|
||||
* 'This' node is not the hole so it obsoletes the new fragment
|
||||
* either fully or partially.
|
||||
*/
|
||||
if (this->ofs + this->size >= fn_ofs + fn_size) {
|
||||
/* The new node is obsolete, drop it */
|
||||
if (fn->frags == 0) {
|
||||
dbg_fragtree2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size);
|
||||
ref_flag = REF_OBSOLETE;
|
||||
}
|
||||
goto out_ok;
|
||||
} else {
|
||||
struct jffs2_node_frag *new_this;
|
||||
|
||||
/* 'This' node obsoletes the beginning of the new node */
|
||||
dbg_fragtree2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size);
|
||||
|
||||
ref_flag = REF_NORMAL;
|
||||
|
||||
fn_size -= this->ofs + this->size - fn_ofs;
|
||||
fn_ofs = this->ofs + this->size;
|
||||
dbg_fragtree2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size);
|
||||
|
||||
new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb);
|
||||
if (!new_this) {
|
||||
/*
|
||||
* There is no next fragment. Add the rest of
|
||||
* the new node as the right-hand child.
|
||||
*/
|
||||
if (!checked) {
|
||||
err = check_node(c, f, tn);
|
||||
if (unlikely(err != 0))
|
||||
return err;
|
||||
checked = 1;
|
||||
}
|
||||
|
||||
fn->frags += 1;
|
||||
newfrag = new_fragment(fn, fn_ofs, fn_size);
|
||||
if (unlikely(!newfrag))
|
||||
return -ENOMEM;
|
||||
|
||||
dbg_fragtree2("there are no more fragments, insert %#04x-%#04x\n",
|
||||
newfrag->ofs, newfrag->ofs + newfrag->size);
|
||||
rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
|
||||
rb_insert_color(&newfrag->rb, root);
|
||||
goto out_ok;
|
||||
} else {
|
||||
this = new_this;
|
||||
dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
|
||||
this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out_ok:
|
||||
BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE);
|
||||
|
||||
if (ref_flag == REF_OBSOLETE) {
|
||||
dbg_fragtree2("the node is obsolete now\n");
|
||||
/* jffs2_mark_node_obsolete() will adjust space accounting */
|
||||
jffs2_mark_node_obsolete(c, fn->raw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dbg_fragtree2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE");
|
||||
|
||||
/* Space accounting was adjusted at check_node_data() */
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
|
||||
{
|
||||
spin_lock(&c->inocache_lock);
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __JFFS2_NODELIST_H__
|
||||
@ -40,6 +38,9 @@
|
||||
#define cpu_to_je32(x) ((jint32_t){x})
|
||||
#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
|
||||
|
||||
#define constant_cpu_to_je16(x) ((jint16_t){x})
|
||||
#define constant_cpu_to_je32(x) ((jint32_t){x})
|
||||
|
||||
#define je16_to_cpu(x) ((x).v16)
|
||||
#define je32_to_cpu(x) ((x).v32)
|
||||
#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
|
||||
@ -48,6 +49,9 @@
|
||||
#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
|
||||
#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
|
||||
|
||||
#define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_be16(x)})
|
||||
#define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_be32(x)})
|
||||
|
||||
#define je16_to_cpu(x) (be16_to_cpu(x.v16))
|
||||
#define je32_to_cpu(x) (be32_to_cpu(x.v32))
|
||||
#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
|
||||
@ -56,6 +60,9 @@
|
||||
#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
|
||||
#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
|
||||
|
||||
#define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_le16(x)})
|
||||
#define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_le32(x)})
|
||||
|
||||
#define je16_to_cpu(x) (le16_to_cpu(x.v16))
|
||||
#define je32_to_cpu(x) (le32_to_cpu(x.v32))
|
||||
#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
|
||||
@ -216,7 +223,20 @@ struct jffs2_tmp_dnode_info
|
||||
uint32_t version;
|
||||
uint32_t data_crc;
|
||||
uint32_t partial_crc;
|
||||
uint32_t csize;
|
||||
uint16_t csize;
|
||||
uint16_t overlapped;
|
||||
};
|
||||
|
||||
/* Temporary data structure used during readinode. */
|
||||
struct jffs2_readinode_info
|
||||
{
|
||||
struct rb_root tn_root;
|
||||
struct jffs2_tmp_dnode_info *mdata_tn;
|
||||
uint32_t highest_version;
|
||||
uint32_t latest_mctime;
|
||||
uint32_t mctime_ver;
|
||||
struct jffs2_full_dirent *fds;
|
||||
struct jffs2_raw_node_ref *latest_ref;
|
||||
};
|
||||
|
||||
struct jffs2_full_dirent
|
||||
@ -319,6 +339,15 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
|
||||
#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
|
||||
#define frag_erase(frag, list) rb_erase(&frag->rb, list);
|
||||
|
||||
#define tn_next(tn) rb_entry(rb_next(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
|
||||
#define tn_prev(tn) rb_entry(rb_prev(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
|
||||
#define tn_parent(tn) rb_entry(rb_parent(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
|
||||
#define tn_left(tn) rb_entry((tn)->rb.rb_left, struct jffs2_tmp_dnode_info, rb)
|
||||
#define tn_right(tn) rb_entry((tn)->rb.rb_right, struct jffs2_tmp_dnode_info, rb)
|
||||
#define tn_erase(tn, list) rb_erase(&tn->rb, list);
|
||||
#define tn_last(list) rb_entry(rb_last(list), struct jffs2_tmp_dnode_info, rb)
|
||||
#define tn_first(list) rb_entry(rb_first(list), struct jffs2_tmp_dnode_info, rb)
|
||||
|
||||
/* nodelist.c */
|
||||
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
|
||||
void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
|
||||
@ -333,8 +362,7 @@ struct rb_node *rb_next(struct rb_node *);
|
||||
struct rb_node *rb_prev(struct rb_node *);
|
||||
void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
|
||||
int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
|
||||
void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
|
||||
int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn);
|
||||
uint32_t jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
|
||||
struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
|
||||
struct jffs2_eraseblock *jeb,
|
||||
uint32_t ofs, uint32_t len,
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: nodemgmt.c,v 1.127 2005/09/20 15:49:12 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -172,6 +170,11 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
{
|
||||
|
||||
if (c->nextblock == NULL) {
|
||||
D1(printk(KERN_DEBUG "jffs2_close_nextblock: Erase block at 0x%08x has already been placed in a list\n",
|
||||
jeb->offset));
|
||||
return;
|
||||
}
|
||||
/* Check, if we have a dirty block now, or if it was dirty already */
|
||||
if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
|
||||
c->dirty_size += jeb->wasted_size;
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2002-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: os-linux.h,v 1.64 2005/09/30 13:59:13 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __JFFS2_OS_LINUX_H__
|
||||
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PUSHPULL_H__
|
||||
#define __PUSHPULL_H__
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
struct pushpull {
|
||||
unsigned char *buf;
|
||||
unsigned int buflen;
|
||||
unsigned int ofs;
|
||||
unsigned int reserve;
|
||||
};
|
||||
|
||||
|
||||
static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve)
|
||||
{
|
||||
pp->buf = buf;
|
||||
pp->buflen = buflen;
|
||||
pp->ofs = ofs;
|
||||
pp->reserve = reserve;
|
||||
}
|
||||
|
||||
static inline int pushbit(struct pushpull *pp, int bit, int use_reserved)
|
||||
{
|
||||
if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (bit) {
|
||||
pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7)));
|
||||
}
|
||||
else {
|
||||
pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7)));
|
||||
}
|
||||
pp->ofs++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pushedbits(struct pushpull *pp)
|
||||
{
|
||||
return pp->ofs;
|
||||
}
|
||||
|
||||
static inline int pullbit(struct pushpull *pp)
|
||||
{
|
||||
int bit;
|
||||
|
||||
bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1;
|
||||
|
||||
pp->ofs++;
|
||||
return bit;
|
||||
}
|
||||
|
||||
static inline int pulledbits(struct pushpull *pp)
|
||||
{
|
||||
return pp->ofs;
|
||||
}
|
||||
|
||||
#endif /* __PUSHPULL_H__ */
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: scan.c,v 1.125 2005/09/30 13:59:13 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
@ -636,16 +635,17 @@ scan_more:
|
||||
|
||||
if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
|
||||
uint32_t inbuf_ofs;
|
||||
uint32_t empty_start;
|
||||
uint32_t empty_start, scan_end;
|
||||
|
||||
empty_start = ofs;
|
||||
ofs += 4;
|
||||
scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len);
|
||||
|
||||
D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
|
||||
more_empty:
|
||||
inbuf_ofs = ofs - buf_ofs;
|
||||
while (inbuf_ofs < buf_len) {
|
||||
if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
|
||||
while (inbuf_ofs < scan_end) {
|
||||
if (unlikely(*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)) {
|
||||
printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
|
||||
empty_start, ofs);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start)))
|
||||
@ -666,7 +666,11 @@ scan_more:
|
||||
D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
|
||||
return BLK_STATE_CLEANMARKER;
|
||||
}
|
||||
|
||||
if (!buf_size && (scan_end != buf_len)) {/* XIP/point case */
|
||||
scan_end = buf_len;
|
||||
goto more_empty;
|
||||
}
|
||||
|
||||
/* See how much more there is to read in this eraseblock... */
|
||||
buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
|
||||
if (!buf_len) {
|
||||
@ -676,6 +680,8 @@ scan_more:
|
||||
empty_start));
|
||||
break;
|
||||
}
|
||||
/* point never reaches here */
|
||||
scan_end = buf_len;
|
||||
D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
|
||||
err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
|
||||
if (err)
|
||||
@ -734,18 +740,8 @@ scan_more:
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
/* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */
|
||||
if (!je32_to_cpu(node->hdr_crc) && !je16_to_cpu(node->nodetype) &&
|
||||
!je16_to_cpu(node->magic) && !je32_to_cpu(node->totlen)) {
|
||||
noisy_printk(&noise, "jffs2_scan_eraseblock(): All zero node header at 0x%08x.\n", ofs);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ofs + je32_to_cpu(node->totlen) >
|
||||
jeb->offset + c->sector_size) {
|
||||
if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) {
|
||||
/* Eep. Node goes over the end of the erase block. */
|
||||
printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
|
||||
ofs, je32_to_cpu(node->totlen));
|
||||
@ -952,8 +948,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
|
||||
struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s)
|
||||
{
|
||||
struct jffs2_inode_cache *ic;
|
||||
uint32_t ino = je32_to_cpu(ri->ino);
|
||||
int err;
|
||||
uint32_t crc, ino = je32_to_cpu(ri->ino);
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
|
||||
|
||||
@ -966,21 +961,22 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
|
||||
Which means that the _full_ amount of time to get to proper write mode with GC
|
||||
operational may actually be _longer_ than before. Sucks to be me. */
|
||||
|
||||
/* Check the node CRC in any case. */
|
||||
crc = crc32(0, ri, sizeof(*ri)-8);
|
||||
if (crc != je32_to_cpu(ri->node_crc)) {
|
||||
printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on "
|
||||
"node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
|
||||
ofs, je32_to_cpu(ri->node_crc), crc);
|
||||
/*
|
||||
* We believe totlen because the CRC on the node
|
||||
* _header_ was OK, just the node itself failed.
|
||||
*/
|
||||
return jffs2_scan_dirty_space(c, jeb,
|
||||
PAD(je32_to_cpu(ri->totlen)));
|
||||
}
|
||||
|
||||
ic = jffs2_get_ino_cache(c, ino);
|
||||
if (!ic) {
|
||||
/* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
|
||||
first node we found for this inode. Do a CRC check to protect against the former
|
||||
case */
|
||||
uint32_t crc = crc32(0, ri, sizeof(*ri)-8);
|
||||
|
||||
if (crc != je32_to_cpu(ri->node_crc)) {
|
||||
printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
|
||||
ofs, je32_to_cpu(ri->node_crc), crc);
|
||||
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen)))))
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
ic = jffs2_scan_make_ino_cache(c, ino);
|
||||
if (!ic)
|
||||
return -ENOMEM;
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
* Copyright © 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
|
@ -1,16 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* Zoltan Sogor <weth@inf.u-szeged.hu>,
|
||||
* Patrik Kluba <pajko@halom.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
* 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* Zoltan Sogor <weth@inf.u-szeged.hu>,
|
||||
* Patrik Kluba <pajko@halom.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
* 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: summary.c,v 1.4 2005/09/26 11:37:21 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -1,15 +1,13 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* Zoltan Sogor <weth@inf.u-szeged.hu>,
|
||||
* Patrik Kluba <pajko@halom.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
||||
* Zoltan Sogor <weth@inf.u-szeged.hu>,
|
||||
* Patrik Kluba <pajko@halom.u-szeged.hu>,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: summary.h,v 1.2 2005/09/26 11:37:21 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef JFFS2_SUMMARY_H
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -347,7 +345,7 @@ static int __init init_jffs2_fs(void)
|
||||
#ifdef CONFIG_JFFS2_SUMMARY
|
||||
" (SUMMARY) "
|
||||
#endif
|
||||
" (C) 2001-2006 Red Hat, Inc.\n");
|
||||
" © 2001-2006 Red Hat, Inc.\n");
|
||||
|
||||
jffs2_inode_cachep = kmem_cache_create("jffs2_i",
|
||||
sizeof(struct jffs2_inode_info),
|
||||
|
@ -1,17 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: symlink.c,v 1.19 2005/11/07 11:14:42 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
|
@ -1,16 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de>
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
* Copyright © 2004 Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
* Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -345,6 +343,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
||||
return;
|
||||
}
|
||||
|
||||
/* The summary is not recovered, so it must be disabled for this erase block */
|
||||
jffs2_sum_disable_collecting(c->summary);
|
||||
|
||||
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
|
||||
@ -967,9 +968,9 @@ exit:
|
||||
|
||||
static const struct jffs2_unknown_node oob_cleanmarker =
|
||||
{
|
||||
.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
|
||||
.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
|
||||
.totlen = cpu_to_je32(8)
|
||||
.magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK),
|
||||
.nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
|
||||
.totlen = constant_cpu_to_je32(8)
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001-2003 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -507,8 +505,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
||||
uint32_t alloclen;
|
||||
int ret;
|
||||
|
||||
if (1 /* alternative branch needs testing */ ||
|
||||
!jffs2_can_mark_obsolete(c)) {
|
||||
if (!jffs2_can_mark_obsolete(c)) {
|
||||
/* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
|
||||
|
||||
rd = jffs2_alloc_raw_dirent();
|
||||
|
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Red Hat, Inc.
|
||||
* Copyright © 2001-2007 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: writev.c,v 1.8 2005/09/09 15:11:58 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
* Copyright © 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
* Copyright © 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JFFS2_FS_XATTR_H_
|
||||
#define _JFFS2_FS_XATTR_H_
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
* Copyright © 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jffs2.h>
|
||||
|
@ -1,13 +1,14 @@
|
||||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
* Copyright © 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jffs2.h>
|
||||
|
@ -1,98 +0,0 @@
|
||||
/* $Id: iflash.h,v 1.2 2000/11/13 18:01:54 dwmw2 Exp $ */
|
||||
|
||||
#ifndef __MTD_IFLASH_H__
|
||||
#define __MTD_IFLASH_H__
|
||||
|
||||
/* Extended CIS registers for Series 2 and 2+ cards */
|
||||
/* The registers are all offsets from 0x4000 */
|
||||
#define CISREG_CSR 0x0100
|
||||
#define CISREG_WP 0x0104
|
||||
#define CISREG_RDYBSY 0x0140
|
||||
|
||||
/* Extended CIS registers for Series 2 cards */
|
||||
#define CISREG_SLEEP 0x0118
|
||||
#define CISREG_RDY_MASK 0x0120
|
||||
#define CISREG_RDY_STATUS 0x0130
|
||||
|
||||
/* Extended CIS registers for Series 2+ cards */
|
||||
#define CISREG_VCR 0x010c
|
||||
|
||||
/* Card Status Register */
|
||||
#define CSR_SRESET 0x20 /* Soft reset */
|
||||
#define CSR_CMWP 0x10 /* Common memory write protect */
|
||||
#define CSR_PWRDOWN 0x08 /* Power down status */
|
||||
#define CSR_CISWP 0x04 /* Common memory CIS WP */
|
||||
#define CSR_WP 0x02 /* Mechanical write protect */
|
||||
#define CSR_READY 0x01 /* Ready/busy status */
|
||||
|
||||
/* Write Protection Register */
|
||||
#define WP_BLKEN 0x04 /* Enable block locking */
|
||||
#define WP_CMWP 0x02 /* Common memory write protect */
|
||||
#define WP_CISWP 0x01 /* Common memory CIS WP */
|
||||
|
||||
/* Voltage Control Register */
|
||||
#define VCR_VCC_LEVEL 0x80 /* 0 = 5V, 1 = 3.3V */
|
||||
#define VCR_VPP_VALID 0x02 /* Vpp Valid */
|
||||
#define VCR_VPP_GEN 0x01 /* Integrated Vpp generator */
|
||||
|
||||
/* Ready/Busy Mode Register */
|
||||
#define RDYBSY_RACK 0x02 /* Ready acknowledge */
|
||||
#define RDYBSY_MODE 0x01 /* 1 = high performance */
|
||||
|
||||
#define LOW(x) ((x) & 0xff)
|
||||
|
||||
/* 28F008SA-Compatible Command Set */
|
||||
#define IF_READ_ARRAY 0xffff
|
||||
#define IF_INTEL_ID 0x9090
|
||||
#define IF_READ_CSR 0x7070
|
||||
#define IF_CLEAR_CSR 0x5050
|
||||
#define IF_WRITE 0x4040
|
||||
#define IF_BLOCK_ERASE 0x2020
|
||||
#define IF_ERASE_SUSPEND 0xb0b0
|
||||
#define IF_CONFIRM 0xd0d0
|
||||
|
||||
/* 28F016SA Performance Enhancement Commands */
|
||||
#define IF_READ_PAGE 0x7575
|
||||
#define IF_PAGE_SWAP 0x7272
|
||||
#define IF_SINGLE_LOAD 0x7474
|
||||
#define IF_SEQ_LOAD 0xe0e0
|
||||
#define IF_PAGE_WRITE 0x0c0c
|
||||
#define IF_RDY_MODE 0x9696
|
||||
#define IF_RDY_LEVEL 0x0101
|
||||
#define IF_RDY_PULSE_WRITE 0x0202
|
||||
#define IF_RDY_PULSE_ERASE 0x0303
|
||||
#define IF_RDY_DISABLE 0x0404
|
||||
#define IF_LOCK_BLOCK 0x7777
|
||||
#define IF_UPLOAD_STATUS 0x9797
|
||||
#define IF_READ_ESR 0x7171
|
||||
#define IF_ERASE_UNLOCKED 0xa7a7
|
||||
#define IF_SLEEP 0xf0f0
|
||||
#define IF_ABORT 0x8080
|
||||
#define IF_UPLOAD_DEVINFO 0x9999
|
||||
|
||||
/* Definitions for Compatible Status Register */
|
||||
#define CSR_WR_READY 0x8080 /* Write state machine status */
|
||||
#define CSR_ERA_SUSPEND 0x4040 /* Erase suspend status */
|
||||
#define CSR_ERA_ERR 0x2020 /* Erase status */
|
||||
#define CSR_WR_ERR 0x1010 /* Data write status */
|
||||
#define CSR_VPP_LOW 0x0808 /* Vpp status */
|
||||
|
||||
/* Definitions for Global Status Register */
|
||||
#define GSR_WR_READY 0x8080 /* Write state machine status */
|
||||
#define GSR_OP_SUSPEND 0x4040 /* Operation suspend status */
|
||||
#define GSR_OP_ERR 0x2020 /* Device operation status */
|
||||
#define GSR_SLEEP 0x1010 /* Device sleep status */
|
||||
#define GSR_QUEUE_FULL 0x0808 /* Queue status */
|
||||
#define GSR_PAGE_AVAIL 0x0404 /* Page buffer available status */
|
||||
#define GSR_PAGE_READY 0x0202 /* Page buffer status */
|
||||
#define GSR_PAGE_SELECT 0x0101 /* Page buffer select status */
|
||||
|
||||
/* Definitions for Block Status Register */
|
||||
#define BSR_READY 0x8080 /* Block status */
|
||||
#define BSR_UNLOCK 0x4040 /* Block lock status */
|
||||
#define BSR_FAILED 0x2020 /* Block operation status */
|
||||
#define BSR_ABORTED 0x1010 /* Operation abort status */
|
||||
#define BSR_QUEUE_FULL 0x0808 /* Queue status */
|
||||
#define BSR_VPP_LOW 0x0404 /* Vpp status */
|
||||
|
||||
#endif /* __MTD_IFLASH_H__ */
|
@ -53,6 +53,7 @@ struct mtd_erase_region_info {
|
||||
u_int32_t offset; /* At which this region starts, from the beginning of the MTD */
|
||||
u_int32_t erasesize; /* For this region */
|
||||
u_int32_t numblocks; /* Number of blocks of erasesize in this region */
|
||||
unsigned long *lockmap; /* If keeping bitmap of locks */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -431,6 +431,7 @@ struct nand_chip {
|
||||
#define NAND_MFR_RENESAS 0x07
|
||||
#define NAND_MFR_STMICRO 0x20
|
||||
#define NAND_MFR_HYNIX 0xad
|
||||
#define NAND_MFR_MICRON 0x2c
|
||||
|
||||
/**
|
||||
* struct nand_flash_dev - NAND Flash Device ID Structure
|
||||
|
Loading…
Reference in New Issue
Block a user