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

📄 ftl.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Invalidate cache */	part->bam_index = 0xffff;	ret = part->mbd.mtd->read(part->mbd.mtd,		       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),		       part->BlocksPerUnit * sizeof(u_int32_t),		       &retlen, (u_char *) (part->bam_cache));	if (ret) {	    printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");	    return 0;	}	part->bam_index = eun;    }    /* Find a free block */    for (blk = 0; blk < part->BlocksPerUnit; blk++)	if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;    if (blk == part->BlocksPerUnit) {#ifdef PSYCHO_DEBUG	static int ne = 0;	if (++ne == 1)	    dump_lists(part);#endif	printk(KERN_NOTICE "ftl_cs: bad free list!\n");	return 0;    }    DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);    return blk;} /* find_free *//*======================================================================    Read a series of sectors from an FTL partition.======================================================================*/static int ftl_read(partition_t *part, caddr_t buffer,		    u_long sector, u_long nblocks){    u_int32_t log_addr, bsize;    u_long i;    int ret;    size_t offset, retlen;    DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",	  part, sector, nblocks);    if (!(part->state & FTL_FORMATTED)) {	printk(KERN_NOTICE "ftl_cs: bad partition\n");	return -EIO;    }    bsize = 1 << part->header.EraseUnitSize;    for (i = 0; i < nblocks; i++) {	if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {	    printk(KERN_NOTICE "ftl_cs: bad read offset\n");	    return -EIO;	}	log_addr = part->VirtualBlockMap[sector+i];	if (log_addr == 0xffffffff)	    memset(buffer, 0, SECTOR_SIZE);	else {	    offset = (part->EUNInfo[log_addr / bsize].Offset			  + (log_addr % bsize));	    ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,			   &retlen, (u_char *) buffer);	    if (ret) {		printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");		return ret;	    }	}	buffer += SECTOR_SIZE;    }    return 0;} /* ftl_read *//*======================================================================    Write a series of sectors to an FTL partition======================================================================*/static int set_bam_entry(partition_t *part, u_int32_t log_addr,			 u_int32_t virt_addr){    u_int32_t bsize, blk, le_virt_addr;#ifdef PSYCHO_DEBUG    u_int32_t old_addr;#endif    u_int16_t eun;    int ret;    size_t retlen, offset;    DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",	  part, log_addr, virt_addr);    bsize = 1 << part->header.EraseUnitSize;    eun = log_addr / bsize;    blk = (log_addr % bsize) / SECTOR_SIZE;    offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +		  le32_to_cpu(part->header.BAMOffset));#ifdef PSYCHO_DEBUG    ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),                        &retlen, (u_char *)&old_addr);    if (ret) {	printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);	return ret;    }    old_addr = le32_to_cpu(old_addr);    if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||	((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||	(!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {	static int ne = 0;	if (++ne < 5) {	    printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");	    printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"		   ", new = 0x%x\n", log_addr, old_addr, virt_addr);	}	return -EIO;    }#endif    le_virt_addr = cpu_to_le32(virt_addr);    if (part->bam_index == eun) {#ifdef PSYCHO_DEBUG	if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {	    static int ne = 0;	    if (++ne < 5) {		printk(KERN_NOTICE "ftl_cs: set_bam_entry() "		       "inconsistency!\n");		printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"		       " = 0x%x\n",		       le32_to_cpu(part->bam_cache[blk]), old_addr);	    }	    return -EIO;	}#endif	part->bam_cache[blk] = le_virt_addr;    }    ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),                            &retlen, (u_char *)&le_virt_addr);    if (ret) {	printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");	printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",	       log_addr, virt_addr);    }    return ret;} /* set_bam_entry */static int ftl_write(partition_t *part, caddr_t buffer,		     u_long sector, u_long nblocks){    u_int32_t bsize, log_addr, virt_addr, old_addr, blk;    u_long i;    int ret;    size_t retlen, offset;    DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",	  part, sector, nblocks);    if (!(part->state & FTL_FORMATTED)) {	printk(KERN_NOTICE "ftl_cs: bad partition\n");	return -EIO;    }    /* See if we need to reclaim space, before we start */    while (part->FreeTotal < nblocks) {	ret = reclaim_block(part);	if (ret)	    return ret;    }    bsize = 1 << part->header.EraseUnitSize;    virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;    for (i = 0; i < nblocks; i++) {	if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {	    printk(KERN_NOTICE "ftl_cs: bad write offset\n");	    return -EIO;	}	/* Grab a free block */	blk = find_free(part);	if (blk == 0) {	    static int ne = 0;	    if (++ne < 5)		printk(KERN_NOTICE "ftl_cs: internal error: "		       "no free blocks!\n");	    return -ENOSPC;	}	/* Tag the BAM entry, and write the new block */	log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;	part->EUNInfo[part->bam_index].Free--;	part->FreeTotal--;	if (set_bam_entry(part, log_addr, 0xfffffffe))	    return -EIO;	part->EUNInfo[part->bam_index].Deleted++;	offset = (part->EUNInfo[part->bam_index].Offset +		      blk * SECTOR_SIZE);	ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,                                     buffer);	if (ret) {	    printk(KERN_NOTICE "ftl_cs: block write failed!\n");	    printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"		   " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,		   offset);	    return -EIO;	}	/* Only delete the old entry when the new entry is ready */	old_addr = part->VirtualBlockMap[sector+i];	if (old_addr != 0xffffffff) {	    part->VirtualBlockMap[sector+i] = 0xffffffff;	    part->EUNInfo[old_addr/bsize].Deleted++;	    if (set_bam_entry(part, old_addr, 0))		return -EIO;	}	/* Finally, set up the new pointers */	if (set_bam_entry(part, log_addr, virt_addr))	    return -EIO;	part->VirtualBlockMap[sector+i] = log_addr;	part->EUNInfo[part->bam_index].Deleted--;	buffer += SECTOR_SIZE;	virt_addr += SECTOR_SIZE;    }    return 0;} /* ftl_write */static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo){	partition_t *part = (void *)dev;	u_long sect;	/* Sort of arbitrary: round size down to 4KiB boundary */	sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;	geo->heads = 1;	geo->sectors = 8;	geo->cylinders = sect >> 3;	return 0;}static int ftl_readsect(struct mtd_blktrans_dev *dev,			      unsigned long block, char *buf){	return ftl_read((void *)dev, buf, block, 1);}static int ftl_writesect(struct mtd_blktrans_dev *dev,			      unsigned long block, char *buf){	return ftl_write((void *)dev, buf, block, 1);}static int ftl_discardsect(struct mtd_blktrans_dev *dev,			   unsigned long sector, unsigned nr_sects){	partition_t *part = (void *)dev;	uint32_t bsize = 1 << part->header.EraseUnitSize;	DEBUG(1, "FTL erase sector %ld for %d sectors\n",	      sector, nr_sects);	while (nr_sects) {		uint32_t old_addr = part->VirtualBlockMap[sector];		if (old_addr != 0xffffffff) {			part->VirtualBlockMap[sector] = 0xffffffff;			part->EUNInfo[old_addr/bsize].Deleted++;			if (set_bam_entry(part, old_addr, 0))				return -EIO;		}		nr_sects--;		sector++;	}	return 0;}/*====================================================================*/static void ftl_freepart(partition_t *part){	vfree(part->VirtualBlockMap);	part->VirtualBlockMap = NULL;	kfree(part->VirtualPageMap);	part->VirtualPageMap = NULL;	kfree(part->EUNInfo);	part->EUNInfo = NULL;	kfree(part->XferInfo);	part->XferInfo = NULL;	kfree(part->bam_cache);	part->bam_cache = NULL;} /* ftl_freepart */static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd){	partition_t *partition;	partition = kzalloc(sizeof(partition_t), GFP_KERNEL);	if (!partition) {		printk(KERN_WARNING "No memory to scan for FTL on %s\n",		       mtd->name);		return;	}	partition->mbd.mtd = mtd;	if ((scan_header(partition) == 0) &&	    (build_maps(partition) == 0)) {		partition->state = FTL_FORMATTED;#ifdef PCMCIA_DEBUG		printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",		       le32_to_cpu(partition->header.FormattedSize) >> 10);#endif		partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;		partition->mbd.tr = tr;		partition->mbd.devnum = -1;		if (!add_mtd_blktrans_dev((void *)partition))			return;	}	ftl_freepart(partition);	kfree(partition);}static void ftl_remove_dev(struct mtd_blktrans_dev *dev){	del_mtd_blktrans_dev(dev);	ftl_freepart((partition_t *)dev);	kfree(dev);}static struct mtd_blktrans_ops ftl_tr = {	.name		= "ftl",	.major		= FTL_MAJOR,	.part_bits	= PART_BITS,	.blksize 	= SECTOR_SIZE,	.readsect	= ftl_readsect,	.writesect	= ftl_writesect,	.discard	= ftl_discardsect,	.getgeo		= ftl_getgeo,	.add_mtd	= ftl_add_mtd,	.remove_dev	= ftl_remove_dev,	.owner		= THIS_MODULE,};static int init_ftl(void){	return register_mtd_blktrans(&ftl_tr);}static void __exit cleanup_ftl(void){	deregister_mtd_blktrans(&ftl_tr);}module_init(init_ftl);module_exit(cleanup_ftl);MODULE_LICENSE("Dual MPL/GPL");MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");

⌨️ 快捷键说明

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