⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nftl.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Linux driver for NAND Flash Translation Layer      *//* (c) 1999 Machine Vision Holdings, Inc.             *//* Author: David Woodhouse <dwmw2@infradead.org>      *//* $Id: nftl.c,v 1.57 2000/12/01 17:51:54 dwmw2 Exp $ *//*  The contents of this file are distributed under the GNU General  Public License version 2 ("GPL"). The author places no additional  restrictions of any kind on it. However, local legislation in some  countries may restrict the use of the algorithms implemented by this  code in certain circumstances.  The legal note below refers only to the _use_ of the code in the   affected jurisdictions, and does not in any way affect the copying,  distribution and modification of this code, which are permitted, and  indeed required, under the terms of the GPL.  Section 0 of the GPL says: "Activities other than copying, distribution and modification are not  covered by this License; they are outside its scope."  You may copy, distribute and modify this code to your hearts'  content - it's just that in some jurisdictions, you may only _use_  it under the terms of the patent grant below. This puts it in a  similar situation to the ISDN code, which you may need telco  approval to use, and indeed any code which has uses that may be  restricted in law. For example, certain malicious uses of the  networking stack may be illegal, but that doesn't prevent the  networking code from being under GPL.  In fact the ISDN case is worse than this, because modification of  the code automatically invalidates its approval. Modification,  unlike usage, _is_ one of the rights which is protected by the  GPL. Happily, the law in those places where approval is required  doesn't actually prevent you from modifying the code - it's just  that you may not be allowed to _use_ it once you've done so - and  because usage isn't addressed by the GPL, that's just fine.  dwmw2@infradead.org  30/10/0  LEGAL NOTE: The NFTL format is patented by M-Systems.  They have  granted a licence for its use with their DiskOnChip products:    "M-Systems grants a royalty-free, non-exclusive license under    any presently existing M-Systems intellectual property rights    necessary for the design and development of NFTL-compatible    drivers, file systems and utilities to use the data formats with,     and solely to support, M-Systems' DiskOnChip products"  A signed copy of this agreement from M-Systems is kept on file by  Red Hat UK Limited. In the unlikely event that you need access to it,  please contact dwmw2@redhat.com for assistance.  */#define PRERELEASE#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <asm/errno.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/miscdevice.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/malloc.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/blkpg.h>#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#include <linux/mtd/mtd.h>#include <linux/mtd/nftl.h>#include <linux/mtd/compatmac.h>/* maximum number of loops while examining next block, to have a   chance to detect consistency problems (they should never happen   because of the checks done in the mounting */#define MAX_LOOPS 10000/* NFTL block device stuff */#define MAJOR_NR NFTL_MAJOR#define DEVICE_REQUEST nftl_request#define DEVICE_OFF(device)#include <linux/blk.h>#include <linux/hdreg.h>/* Linux-specific block device functions *//* I _HATE_ the Linux block device setup more than anything else I've ever *  encountered, except ... */static int nftl_sizes[256] = {0,};static int nftl_blocksizes[256] = {0,};/* .. for the Linux partition table handling. */struct hd_struct part_table[256] = {{0,0},};#if LINUX_VERSION_CODE < 0x20328static void dummy_init (struct gendisk *crap){}#endifstatic struct gendisk nftl_gendisk = {        MAJOR_NR,     /* Major number */              "nftl",          /* Major name */        4,              /* Bits to shift to get real from partition */        15,             /* Number of partitions per real */#if LINUX_VERSION_CODE < 0x20328        MAX_NFTLS,      /* maximum number of real */        dummy_init,     /* init function */#endif        part_table,     /* hd struct */        nftl_sizes,     /* block sizes */        0,              /* number */        NULL,           /* internal use, not presently used */        NULL            /* next */};struct NFTLrecord *NFTLs[MAX_NFTLS] = {NULL};static void NFTL_setup(struct mtd_info *mtd){	int i;	struct NFTLrecord *nftl;	unsigned long temp;	int firstfree = -1;	DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");	for (i = 0; i < MAX_NFTLS; i++) {		if (!NFTLs[i] && firstfree == -1)			firstfree = i;		else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {			/* This is a Spare Media Header for an NFTL we've already found */			DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");			return;		}	}        if (firstfree == -1) {		printk(KERN_WARNING "No more NFTL slot available\n");		return;        }	nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);	if (!nftl) {		printk(KERN_WARNING "Out of memory for NFTL data structures\n");		return;	}	init_MUTEX(&nftl->mutex);        /* get physical parameters */	nftl->EraseSize = mtd->erasesize;        nftl->nb_blocks = mtd->size / mtd->erasesize;	nftl->mtd = mtd;        if (NFTL_mount(nftl) < 0) {		printk(KERN_WARNING "Could not mount NFTL device\n");		kfree(nftl);		return;        }	/* OK, it's a new one. Set up all the data structures. */#ifdef PSYCHO_DEBUG	printk("Found new NFTL nftl%c\n", firstfree + 'a');#endif        /* linux stuff */	nftl->usecount = 0;	nftl->cylinders = 1024;	nftl->heads = 16;	temp = nftl->cylinders * nftl->heads;	nftl->sectors = nftl->nr_sects / temp;	if (nftl->nr_sects % temp) {		nftl->sectors++;		temp = nftl->cylinders * nftl->sectors;		nftl->heads = nftl->nr_sects / temp;		if (nftl->nr_sects % temp) {			nftl->heads++;			temp = nftl->heads * nftl->sectors;			nftl->cylinders = nftl->nr_sects / temp;		}	}	if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {		printk(KERN_WARNING "Cannot calculate an NFTL geometry to "		       "match size of 0x%lx.\n", nftl->nr_sects);		printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", 		       nftl->cylinders, nftl->heads , nftl->sectors, 		       (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );		/* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */	}	NFTLs[firstfree] = nftl;	/* Finally, set up the block device sizes */	nftl_sizes[firstfree * 16] = nftl->nr_sects;	//nftl_blocksizes[firstfree*16] = 512;	part_table[firstfree * 16].nr_sects = nftl->nr_sects;	/* partition check ... */#if LINUX_VERSION_CODE < 0x20328	resetup_one_dev(&nftl_gendisk, firstfree);#else	grok_partitions(&nftl_gendisk, firstfree, 1<<4, nftl->nr_sects);#endif}static void NFTL_unsetup(int i){	struct NFTLrecord *nftl = NFTLs[i];	DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);		NFTLs[i] = NULL;		if (nftl->ReplUnitTable)		kfree(nftl->ReplUnitTable);	if (nftl->EUNtable)		kfree(nftl->EUNtable);		      	kfree(nftl);}/* Search the MTD device for NFTL partitions */static void NFTL_notify_add(struct mtd_info *mtd){	DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);	if (mtd) {		if (!mtd->read_oob) {			/* If this MTD doesn't have out-of-band data,			   then there's no point continuing */			DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");			return;		}		DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", 		      mtd->read, mtd->size, mtd->erasesize);                NFTL_setup(mtd);	}}static void NFTL_notify_remove(struct mtd_info *mtd){	int i;	for (i = 0; i < MAX_NFTLS; i++) {		if (NFTLs[i] && NFTLs[i]->mtd == mtd)			NFTL_unsetup(i);	}}#ifdef CONFIG_NFTL_RW/* Actual NFTL access routines *//* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used *	when the give Virtual Unit Chain */static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ){	/* For a given Virtual Unit Chain: find or create a free block and	   add it to the chain */	/* We're passed the number of the last EUN in the chain, to save us from	   having to look it up again */	u16 pot = nftl->LastFreeEUN;	int silly = -1;	/* Normally, we force a fold to happen before we run out of free blocks completely */	if (!desperate && nftl->numfreeEUNs < 2) {		DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");		return 0xffff;	}	/* Scan for a free block */	do {		if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {			nftl->LastFreeEUN = pot;			nftl->numfreeEUNs--;			return pot;		}		/* This will probably point to the MediaHdr unit itself,		   right at the beginning of the partition. But that unit		   (and the backup unit too) should have the UCI set		   up so that it's not selected for overwriting */		if (++pot > nftl->lastEUN)			pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);		if (!silly--) {			printk("Argh! No free blocks found! LastFreeEUN = %d, "			       "FirstEUN = %d\n", nftl->LastFreeEUN, 			       le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));			return 0xffff;		}	} while (pot != nftl->LastFreeEUN);	return 0xffff;}static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock ){	u16 BlockMap[MAX_SECTORS_PER_UNIT];	unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];	unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];	unsigned int thisEUN;	int block;	int silly;	unsigned int targetEUN;	struct nftl_oob oob;	int inplace = 1;        size_t retlen;	memset(BlockMap, 0xff, sizeof(BlockMap));	memset(BlockFreeFound, 0, sizeof(BlockFreeFound));	thisEUN = nftl->EUNtable[thisVUC];	if (thisEUN == BLOCK_NIL) {		printk(KERN_WARNING "Trying to fold non-existent "		       "Virtual Unit Chain %d!\n", thisVUC);		return BLOCK_NIL;	}		/* Scan to find the Erase Unit which holds the actual data for each	   512-byte block within the Chain.	*/        silly = MAX_LOOPS;	targetEUN = BLOCK_NIL;	while (thisEUN <= nftl->lastEUN ) {                unsigned int status, foldmark;		targetEUN = thisEUN;		for (block = 0; block < nftl->EraseSize / 512; block ++) {			MTD_READOOB(nftl->mtd,				    (thisEUN * nftl->EraseSize) + (block * 512),				    16 , &retlen, (char *)&oob);			if (block == 2) {                                foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;                                if (foldmark == FOLD_MARK_IN_PROGRESS) {                                        DEBUG(MTD_DEBUG_LEVEL1,                                               "Write Inhibited on EUN %d\n", thisEUN);					inplace = 0;				} else {					/* There's no other reason not to do inplace,					   except ones that come later. So we don't need					   to preserve inplace */					inplace = 1;				}			}                        status = oob.b.Status | oob.b.Status1;			BlockLastState[block] = status;			switch(status) {			case SECTOR_FREE:				BlockFreeFound[block] = 1;				break;			case SECTOR_USED:				if (!BlockFreeFound[block])					BlockMap[block] = thisEUN;				else					printk(KERN_WARNING 					       "SECTOR_USED found after SECTOR_FREE "

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -