📄 ssfdc.c
字号:
// 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 + -