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

📄 ssfdc.c

📁 nandflash k9g808u0a在pxa270的驱动,由于pxa270没有nandflash接口
💻 C
📖 第 1 页 / 共 3 页
字号:
			ssfdc_cached = 0xFFFFFFFF;			memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));			new = ssfdc_allocate_new(pt_smcpart, zone);			PDEBUG("ssfdc_write : zone %d, block %d, lbn %d, physical 0x%x, unallocated, new 0x%x\n",				zone, block, sector, physical, new);		}		if(new != -1) {			memcpy(&ssfdc_scratch[(offset * SECTOR_SIZE)], ptr, size);			PDEBUG("ssfdc_write : new 0x%x, offset 0x%x, size 0x%x, block 0x%x\n", new, offset, size, block);       		for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {				memset(ssfdc_buffer, 0xFF, OOB_SIZE);				nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);				nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);				for(i=0; i<6; i++) ssfdc_buffer[ssfdc_ecc[i]] = ecc_calc[i];				i = (block << 1) | 0x1000;				i |= ssfdc_parity(block);                		ssfdc_buffer[7] = ssfdc_buffer[12] = i & 0xFF;                		ssfdc_buffer[6] = ssfdc_buffer[11] = (i & 0xFF00) >> 0x08;                memcpy(&ssfdc_oob_buf[sc * OOB_SIZE], ssfdc_buffer, OOB_SIZE);			}	   		pt_smcpart->mtd->write_ecc(pt_smcpart->mtd, new, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,                        ssfdc_oob_buf, &ssfdc_ffoob_info);			if(retlen != SMC_BLOCK_SIZE) {				printk(KERN_WARNING "ssfdc_write : failed to write block, physical 0x%x, returned 0x%x\n", new, retlen);				return -ENXIO;			}			/* change the mapping table to reflect the new block placement */			*(pt_logical + block) = (new % ZONE_SIZE) / SMC_BLOCK_SIZE;			PDEBUG("ssfdc_write : logical 0x%x + 0x%x = 0x%x\n",						(unsigned int)pt_logical, block, (new % ZONE_SIZE) / SMC_BLOCK_SIZE);            		*(pt_physical + ((new % ZONE_SIZE) / SMC_BLOCK_SIZE)) = block;			PDEBUG("ssfdc_write : physical 0x%x + 0x%x = 0x%x\n",				(unsigned int)pt_physical, ((new % ZONE_SIZE) / SMC_BLOCK_SIZE), block);			ssfdc_cached = new;   	    }		ptr += size;		ptr_done = 0;		sectors_written += (size / SECTOR_SIZE);		if(do_erase) ssfdc_erase(pt_smcpart, physical);	}	return(0);}static int ssfdc_sector_blank(partition_t * pt_smcpart, int sc) {int b;	for(b=0; b<SECTOR_SIZE; b++) {		if(ssfdc_scratch[b + (sc * SECTOR_SIZE)] != 0xFF) return(0);	}	for(b=0; b<OOB_SIZE; b++) {		if((b==6) || (b==7) || (b==11) || (b==12)) continue;   // Block address fields		if(ssfdc_buffer[b] != 0xFF) return(0);	}    return(1);}static int ssfdc_allocate_new(partition_t * pt_smcpart, int zone) {	int new = pt_smcpart->last_written[zone] + 1;	int * pt_physical;	int physical;    	int block;	int retlen;	unsigned char oob[16];		if(new >= BLOCKS_PER_ZONE) new = 0;	while (new != pt_smcpart->last_written[zone]) {       	block = new % BLOCKS_PER_ZONE;		pt_physical = pt_smcpart->zone + (zone * 2048) + 1024 + block;		physical = (zone * ZONE_SIZE) + (block * SMC_BLOCK_SIZE);	  	PDEBUG("ssfdc_allocate_new : zone %d, block %d, address 0x%08x, data 0x%08x\n",			zone, block, (unsigned int)pt_physical, *pt_physical);     		if(*pt_physical == 0xFFFFFFFF) {			PDEBUG("ssfdc_allocate_new : physical 0x%x = 0x%x\n", (unsigned int)pt_physical, *pt_physical);			memset(oob, 0, OOB_SIZE);			pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical, OOB_SIZE, &retlen, oob);			if((oob[5] == 0xFF) && (retlen == OOB_SIZE)) {   // If not a bad block				pt_smcpart->last_written[zone] = new;				return((new * SMC_BLOCK_SIZE) + (zone * ZONE_SIZE));			}			else {             			PDEBUG("ssfdc_allocate_new : new 0x%x, physical 0x%x, block status 0x%x, oob length 0x%x\n", new, physical, oob[5], retlen);			}		}		new++;		if(new >= BLOCKS_PER_ZONE) new = 0;	}   	panic("ssfdc_allocate_new : cant find free block\n");}	static int ssfdc_read(partition_t *pt_smcpart, caddr_t buffer,		    u_long sector, u_long nblocks){	int zone, block, offset;	int sectors_read = 0;    int physical;	int size;	int retlen;	int i;	int sc;	unsigned char * ptr = (unsigned char *)buffer;	unsigned char ecc_code[6], ecc_calc[6];/*    unsigned char smc_status;  	smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);	if(!(smc_status & SMC_PRESENT)) {		printk("ssfdc : media not present\n");		return -ENXIO;	}    if(smc_status & SMC_CHANGED) {   		out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);		ssfdc_read_partitions(pt_smcpart);		printk("ssfdc : media change\n");	}*/	while(sectors_read < nblocks) {		zone = (sector + sectors_read) / SECTORS_PER_ZONE;		block = ((sector + sectors_read) % SECTORS_PER_ZONE) / SECTORS_PER_BLOCK ;		offset = ((sector + sectors_read) % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;		if(offset) {			size = ((SECTORS_PER_BLOCK - offset) < (nblocks - sectors_read)) ?					(SECTORS_PER_BLOCK - offset) : (nblocks - sectors_read);		}		else {			size = (SECTORS_PER_BLOCK < (nblocks - sectors_read)) ? SECTORS_PER_BLOCK : nblocks - sectors_read;		}		size *= SECTOR_SIZE;	    PDEBUG("ssfdc_read :  device %d, sector %d, count %d, zone %d, block %d, offset %d, done %d, size %d, address 0x%x\n",			pt_smcpart->count, sector, nblocks, zone, block, offset, sectors_read, size, (unsigned int)ptr);					physical = ssfdc_physical(pt_smcpart, zone, block);		if(physical >=  0) {			if(ssfdc_cached != physical) {           		pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, physical, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,													 ssfdc_oob_buf, &ssfdc_ffoob_info);				if(retlen != SMC_BLOCK_SIZE) {					printk(KERN_WARNING "ssfdc_read : failed to read physical\n");					return -ENXIO;				}				for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {	    			pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);					if(retlen != sizeof(ssfdc_buffer)) {						printk(KERN_WARNING "ssfdc_read : failed to read physical oob\n");						return -ENXIO;					}					nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);					nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);					for(i=0; i<3; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];					for(i=3; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];					nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]);					nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]);				}				/* Get the ecc bytes and check that they are ok */			}			ssfdc_cached = physical;								}		else {			memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));			ssfdc_cached = 0xFFFFFFFF;		}					memcpy(ptr, &ssfdc_scratch[(offset * SECTOR_SIZE)], size);		ptr += size;		sectors_read += (size / SECTOR_SIZE);		}	                                                    	return(0);}static void ssfdc_erase_callback(struct erase_info *erase) {	PDEBUG("ssfdc_erase_callback : wake erase\n");    	up(&ssfdc_semaphore);	PDEBUG("ssfdc_erase_callback : woken erase\n");}static int ssfdc_erase(partition_t *pt_smcpart, unsigned int offset){	int ret = 0;    	struct erase_info *erase;	unsigned char * junk;	unsigned char * oob;	int retlen;	int b, sc;	PDEBUG("ssfdc_erase : offset 0x%08x\n", offset);	erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);    	junk=kmalloc(pt_smcpart->mtd->erasesize + 16, GFP_KERNEL);    	oob = junk + pt_smcpart->mtd->erasesize;    	if (!erase)        	 return -ENOMEM;    	if (!junk)        	 return -ENOMEM;    	erase->addr = offset;    	erase->len = pt_smcpart->mtd->erasesize;	erase->callback = ssfdc_erase_callback;    	ret = pt_smcpart->mtd->erase(pt_smcpart->mtd, erase);	if(ret) {     		printk(KERN_WARNING "ssfdc_erase : failed status 0x%x\n", ret);		goto end;	}	down(&ssfdc_semaphore);	pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, offset, SMC_BLOCK_SIZE, &retlen, junk,							 ssfdc_oob_buf, &ssfdc_ffoob_info);	if(retlen != SMC_BLOCK_SIZE) {           	printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read returned length %d\n", offset, retlen);		goto end;	}	for(sc=0; sc < SECTORS_PER_BLOCK; sc++) {		for(b=0; b<SECTOR_SIZE; b++) {			if(*(junk + (b + (sc * SECTOR_SIZE))) != 0xFF) {             			printk(KERN_WARNING "ssfdc_erase : offset 0x%x, sector 0x%x, byte 0x%x, data 0x%02x, expected 0xff\n"						, offset, sc, b, *(junk + (b + (sc * SECTOR_SIZE))));				goto end;			}		}		pt_smcpart->mtd->read_oob(pt_smcpart->mtd, offset + (sc * SECTOR_SIZE), OOB_SIZE, &retlen, oob);		if(retlen != OOB_SIZE) {           		printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read oob returned length %d\n", offset, retlen);			goto end;		}		for(b=0; b<OOB_SIZE; b++) {			if(*(oob+b) != 0xFF) {             			printk(KERN_WARNING "ssfdc_erase : offset 0x%x, byte 0x%x, oob got 0x%02x, expected 0xff\n", 						offset, b, *(oob+b));				goto end;			}		}	}end:	    kfree(erase);	kfree(junk);    return ret;} /* erase_xfer */int init_ssfdc(void){	int result, i;//	unsigned char smc_status;//	#define B01159_FIO_PBASE 0x0000000148000000  /* Physical Base address of SMC control chip  */	printk(KERN_INFO "SSFDC block device translation layer V1.0\n");/*	pt_ssfdc_smc = ioremap64(B01159_FIO_PBASE, 1024);	if(!pt_ssfdc_smc){     	printk("ssfdc : failed to map SMC control device\n");        return(-EFAULT);	}	  	smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);*/	    memset(ssfdc_ffoob_buf, 0xFF, sizeof(ssfdc_ffoob_buf));    	for (i = 0; i < MAX_DEVICES*MAX_PARTITIONS; i++) {		ssfdc_hd[i].nr_sects = 0;		ssfdc_hd[i].start_sect = 0;		ssfdc_blocksizes[i] = 4096;    	}   	blksize_size[SSFDC_MAJOR] = ssfdc_blocksizes;   	ssfdc_gendisk.major = SSFDC_MAJOR;	memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));	result = register_blkdev(ssfdc_major, "ssfdc", &ssfdc_fops);	if(result != 0) {		printk(KERN_WARNING "ssfdc : failed to get a major number\n");		return(result);	}//	if(ssfdc_major == 0) ssfdc_major = result;	    	blk_init_queue(BLK_DEFAULT_QUEUE(ssfdc_major), &do_ssfdc_request);    	add_gendisk(&ssfdc_gendisk);    	register_mtd_user(&ssfdc_notifier);	init_MUTEX_LOCKED(&ssfdc_semaphore);    	return 0;}static void __exit cleanup_ssfdc(void){	int i;	for(i=0; i<MAX_DEVICES; i++) {       		if(SMCParts[i].zone)kfree(SMCParts[i].zone);	}    	unregister_mtd_user(&ssfdc_notifier);    	unregister_blkdev(ssfdc_major, "ssfdc");    	blk_cleanup_queue(BLK_DEFAULT_QUEUE(ssfdc_major));    	blksize_size[SSFDC_MAJOR] = NULL;    	del_gendisk(&ssfdc_gendisk);}module_init(init_ssfdc);module_exit(cleanup_ssfdc);MODULE_LICENSE("GPL");MODULE_AUTHOR("Simon Haynes <simon@baydel.com>");MODULE_DESCRIPTION("SSFDC translation layer support for MTD");

⌨️ 快捷键说明

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