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

📄 ssfdc.c

📁 nandflash k9g808u0a在pxa270的驱动,由于pxa270没有nandflash接口
💻 C
📖 第 1 页 / 共 3 页
字号:
//			printk(KERN_WARNING "ssfdc : HDIO_GETGEO heads %d, sectors %d, cylinders %d, start %lu\n",//				geo.heads, geo.sectors, geo.cylinders, geo.start);			copy_to_user((void *)arg, &geo, sizeof(geo));			ret = 0;		break;	    case BLKGETSIZE64:   	 	case BLKGETSIZE:			size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;			//=printk(KERN_WARNING "ssfdc : BLKGETSIZE %d, minor %d\n", size, minor);			ret = copy_to_user((unsigned long *)arg, &size, sizeof(size));		break;		case BLKSSZGET:			size = 512;			ret = copy_to_user((unsigned long *)arg, &size, sizeof(size));		break;		break;    	case BLKRRPART:				if(minor & ((1<< PARTITION_BITS) - 1)) return -ENOTTY;				ssfdc_read_partitions(pt_smcpart);				ret=0;		break;   		case BLKFLSBUF:			printk(KERN_WARNING "ssfdc : block ioctl 0x%x\n", cmd);		break;   		default:			printk(KERN_WARNING "ssfdc: unknown ioctl 0x%x\n", cmd);    }//ssfdc_ioctl_error:    return(ret);}static int ssfdc_open(struct inode *inode, struct file *file){    int minor = MINOR(inode->i_rdev);    partition_t *pt_smcpart;	int index;    if (minor >= MAX_MTD_DEVICES)	return -ENODEV;    index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;    if(SMCParts[index].type != SSFDC_FORMAT)	return -ENXIO;	pt_smcpart = &SMCParts[index];	if(!pt_smcpart->zone)	return -ENXIO;     BLK_INC_USE_COUNT;    if (!get_mtd_device(pt_smcpart->mtd, -1)) {	    BLK_DEC_USE_COUNT;	    return -ENXIO;    }    if ((file->f_mode & 2) && !(pt_smcpart->mtd->flags & MTD_CLEAR_BITS) ) {	    put_mtd_device(pt_smcpart->mtd);	    BLK_DEC_USE_COUNT;            return -EROFS;    }    atomic_inc(&pt_smcpart->minor[minor & ~(MAX_PARTITIONS -1)].open);	PDEBUG("ssfdc_open : device %d\n", minor);	return(0);}static void ssfdc_tables(partition_t * pt_smcpart) {	int * logical, * physical;	int offset = 0;	int zone, block;	int i, retlen;	int block_address, parity;	int h, l;	for(zone=0; zone<pt_smcpart->zoneCount; zone++) {			logical  =  pt_smcpart->zone + (2048 * zone);		memset((void *)logical, 0xFF, 1024 * sizeof(int));		physical =  pt_smcpart->zone + (2048 * zone) + 1024;		memset((void *)physical, 0xFF, 1024 * sizeof(int));		for(block=0; block < 1024; block++) {			offset = (zone * ZONE_SIZE) + (block * SMC_BLOCK_SIZE);	    		pt_smcpart->mtd->read_oob(pt_smcpart->mtd, offset, sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);			if(retlen != sizeof(ssfdc_buffer)) {				printk(KERN_WARNING "ssfdc_tables : failed to read OOB\n");				pt_smcpart->type = 0;				return;			}			l = (ssfdc_buffer[7] & 0xFF);			h = (ssfdc_buffer[6] & 0xFF);            		block_address = l + (h << 8L);			if((block_address & ~0x7FF) != 0x1000) {					continue;			}			parity = block_address & 0x01;						block_address &= 0x7FF;			block_address >>= 1;			if(ssfdc_parity(block_address) != parity) { 				printk(KERN_WARNING "ssfdc_tables : parity error offset 0x%x, block 0x%x, parity 0x%x\nOOB : "						, offset, block_address, parity);			    	for(i=0; i<16; i++) {                 			printk("0x%02x ", (unsigned char)ssfdc_buffer[i]);			    	}				printk("\n");				pt_smcpart->type = 0;				return;          					}            		/* Ok we have a valid block number so insert it */            		*(logical + block_address) = (offset/SMC_BLOCK_SIZE);			PDEBUG("ssfdc_tables : logical 0x%x + 0x%x = 0x%x\n", 					(unsigned int)logical, block_address, (offset/SMC_BLOCK_SIZE));			*(physical + block) = block_address;			PDEBUG("ssfdc_tables : physical 0x%x + 0x%x = 0x%x\n", (unsigned int)physical, block, block_address);			    		}    	}    	return;}int ssfdc_parity(int number) { 	int i;	int parity = 1; // the 0x1000 bit	for(i=0; i<10; i++) {      		parity += ((number >> i) & 1);	}	PDEBUG("ssfdc_parity : number 0x%x, parity 0x%x\n", number, parity);	return(parity % 2);}static int ssfdc_physical(partition_t * pt_smcpart, int zone, int block) {	unsigned int * logical;	logical = pt_smcpart->zone + (zone * 2048);	logical += block;	if(*logical == 0xFFFFFFFF) {		PDEBUG("ssfdc_physical : physical for zone %d, block %d invalid\n", zone, block);		return(-1);	}	PDEBUG("ssfdc_physical : physical for zone %d, block %d, 0x%x\n", zone, block, (*logical * SMC_BLOCK_SIZE));	return(*logical * SMC_BLOCK_SIZE);}static int ssfdc_close(struct inode *inode, struct file *file){                           int minor = MINOR(inode->i_rdev);    partition_t *pt_smcpart;	int index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;    if (minor >= MAX_MTD_DEVICES)	return -ENODEV;    if(SMCParts[index].type != SSFDC_FORMAT)	return -ENXIO;    pt_smcpart = &SMCParts[index];    atomic_dec(&pt_smcpart->minor[minor & ~(MAX_PARTITIONS -1)].open);    put_mtd_device(pt_smcpart->mtd);    BLK_DEC_USE_COUNT;    return(0);} static void do_ssfdc_request(request_arg_t){    int ret, minor;    partition_t *pt_smcpart;	int index;    do {	INIT_REQUEST;	minor = MINOR(CURRENT->rq_dev);	index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;	pt_smcpart = &SMCParts[index];	if (pt_smcpart->type == SSFDC_FORMAT) { 		ret = 0;		switch (CURRENT->cmd) {			case READ:	  			ret = ssfdc_read(pt_smcpart, CURRENT->buffer,					CURRENT->sector + ssfdc_hd[minor].start_sect,					CURRENT->current_nr_sectors);		    break;		  	case WRITE:		    	ret = ssfdc_write(pt_smcpart, CURRENT->buffer,				    CURRENT->sector	+ ssfdc_hd[minor].start_sect,				    CURRENT->current_nr_sectors);		    break;		  default:		    panic("do_ssfdc_request : unknown block command!\n");		  }		} else {	  ret = 1;	  PDEBUG("not ssfdc partition type\n");	}	if (!ret) {	  CURRENT->sector += CURRENT->current_nr_sectors;	}	end_request((ret == 0) ? 1 : 0);    } while (1);}static int ssfdc_write(partition_t *pt_smcpart, caddr_t buffer,		     u_long sector, u_long nblocks){	int zone, block, offset;	int sectors_written = 0;    	int physical;	int * pt_logical;	int * pt_physical;	int new = -1;	int size;	int retlen;	int i;	int sc;	int ptr_done = 0;	unsigned char * ptr = (unsigned char *)buffer;	unsigned char ecc_code[6], ecc_calc[6];	int do_erase;//	unsigned char smc_status;	offset = (sector % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;    	PDEBUG("write device %d, sector %d, count %d\n",			pt_smcpart->count, sector, nblocks);/*  	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_written < nblocks) {		new = -1;		do_erase = FALSE;    		zone = (sector + sectors_written) / SECTORS_PER_ZONE;		block = ((sector + sectors_written) % SECTORS_PER_ZONE) / SECTORS_PER_BLOCK ;		offset = ((sector + sectors_written) % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;		pt_logical = pt_smcpart->zone + (zone * 2048);		pt_physical = pt_smcpart->zone + (zone * 2048) + 1024;		size = ((SECTORS_PER_BLOCK - offset) < (nblocks - sectors_written)) ?				(SECTORS_PER_BLOCK - offset) : (nblocks - sectors_written);		size *= SECTOR_SIZE;		PDEBUG("write 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_written, 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_write : 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_write : 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<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]);				}			}						for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {				if(offset > sc) {					PDEBUG("offset %d, sector %d\n", offset, sc);					continue;				}   				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_write : 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<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]);								/* find out if the block is being used */				if(ssfdc_sector_blank(pt_smcpart, sc)) {					PDEBUG("ssfdc_write : zone %d, block %d, sector %d, lbn %d, blank, physical 0x%x\n",						zone, block, sc, sector, physical);					memcpy(&ssfdc_scratch[(sc * SECTOR_SIZE)], ptr+ptr_done, SECTOR_SIZE);					nand_calculate_ecc (pt_smcpart->mtd, (ptr + ptr_done), &ecc_calc[0]);					nand_calculate_ecc (pt_smcpart->mtd, (ptr + ptr_done + 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;                    pt_smcpart->mtd->write_ecc(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), SECTOR_SIZE, &retlen,								ptr + ptr_done, ssfdc_buffer, &ssfdc_ffoob_info);					if(retlen != SECTOR_SIZE) {						printk(KERN_WARNING "ssfdc_write : failed to write physical 0x%x, sector 0x%x, blank, retlen %d\n"								, physical, sc, retlen);						return -ENXIO;					}                    ptr_done += SECTOR_SIZE;					if(ptr_done >= size) break;				}				else {					new = ssfdc_allocate_new(pt_smcpart, zone);					/* erase the old block */		            *(pt_physical + ((physical % ZONE_SIZE) / SMC_BLOCK_SIZE)) = 0xFFFFFFFF;					PDEBUG("ssfdc_write : physical 0x%x + 0x%x = 0x%x\n",						(unsigned int)pt_physical, ((physical % ZONE_SIZE) / SMC_BLOCK_SIZE), 0xFFFFFFFF);					do_erase = TRUE;					PDEBUG("ssfdc_write : zone %d, block %d, sector %d, lbn %d, written, physical 0x%x, new 0x%x\n",						zone, block, sc, sector, physical, new);					break;				}			}		}		else {

⌨️ 快捷键说明

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