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

📄 ftl.c

📁 这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,CD MP3...有很好的参考价值.
💻 C
📖 第 1 页 / 共 3 页
字号:
	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->mtd->read(part->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->mtd->read(part->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->mtd->write(part->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->mtd->write(part->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%x\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 *//*======================================================================    IOCTL calls for getting device parameters.======================================================================*/static int ftl_ioctl(struct inode *inode, struct file *file,		     u_int cmd, u_long arg){    struct hd_geometry *geo = (struct hd_geometry *)arg;    int ret = 0, minor = MINOR(inode->i_rdev);    partition_t *part= myparts[minor >> 4];    u_long sect;    if (!part)	return -ENODEV; /* How? */    switch (cmd) {    case HDIO_GETGEO:	ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));	if (ret) return ret;	/* Sort of arbitrary: round size down to 4K boundary */	sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;	put_user(1, (char *)&geo->heads);	put_user(8, (char *)&geo->sectors);	put_user((sect>>3), (short *)&geo->cylinders);	put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);	break;    case BLKGETSIZE:	ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);	break;    case BLKGETSIZE64:	ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);	break;    case BLKRRPART:	ret = ftl_reread_partitions(minor);	break;#if (LINUX_VERSION_CODE < 0x20303)    case BLKFLSBUF:#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)	if (!capable(CAP_SYS_ADMIN)) return -EACCES;#endif	fsync_dev(inode->i_rdev);	invalidate_buffers(inode->i_rdev);	break;    RO_IOCTLS(inode->i_rdev, arg);#else    case BLKROSET:    case BLKROGET:    case BLKFLSBUF:	ret = blk_ioctl(inode->i_rdev, cmd, arg);	break;#endif    default:	ret = -EINVAL;    }    return ret;} /* ftl_ioctl *//*======================================================================    Handler for block device requests======================================================================*/static int ftl_reread_partitions(int minor){    partition_t *part = myparts[minor >> 4];    int i, whole;    DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);    if ((atomic_read(&part->open) > 1)) {	    return -EBUSY;    }    whole = minor & ~(MAX_PART-1);    i = MAX_PART - 1;    while (i-- > 0) {	if (ftl_hd[whole+i].nr_sects > 0) {	    kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);	    invalidate_device(rdev, 1);	}	ftl_hd[whole+i].start_sect = 0;	ftl_hd[whole+i].nr_sects = 0;    }    scan_header(part);    register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,		  &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);#ifdef PCMCIA_DEBUG    for (i = 0; i < MAX_PART; i++) {	if (ftl_hd[whole+i].nr_sects > 0)	    printk(KERN_INFO "  %d: start %ld size %ld\n", i,		   ftl_hd[whole+i].start_sect,		   ftl_hd[whole+i].nr_sects);    }#endif    return 0;}/*======================================================================    Handler for block device requests======================================================================*/static void do_ftl_request(request_arg_t){    int ret, minor;    partition_t *part;    do {      //	    sti();	INIT_REQUEST;	minor = MINOR(CURRENT->rq_dev);		part = myparts[minor >> 4];	if (part) {	  ret = 0;	  	  switch (CURRENT->cmd) {	  case READ:	    ret = ftl_read(part, CURRENT->buffer,			   CURRENT->sector+ftl_hd[minor].start_sect,			   CURRENT->current_nr_sectors);	    if (ret) printk("ftl_read returned %d\n", ret);	    break;	    	  case WRITE:	    ret = ftl_write(part, CURRENT->buffer,			    CURRENT->sector+ftl_hd[minor].start_sect,			    CURRENT->current_nr_sectors);	    if (ret) printk("ftl_write returned %d\n", ret);	    break;	    	  default:	    panic("ftl_cs: unknown block command!\n");	    	  }	} else {	  ret = 1;	  printk("NULL part in ftl_request\n");	}	 	if (!ret) {	  CURRENT->sector += CURRENT->current_nr_sectors;	}		end_request((ret == 0) ? 1 : 0);    } while (1);} /* do_ftl_request *//*====================================================================*/void ftl_freepart(partition_t *part){    if (part->VirtualBlockMap) {	vfree(part->VirtualBlockMap);	part->VirtualBlockMap = NULL;    }    if (part->VirtualPageMap) {	kfree(part->VirtualPageMap);	part->VirtualPageMap = NULL;    }    if (part->EUNInfo) {	kfree(part->EUNInfo);	part->EUNInfo = NULL;    }    if (part->XferInfo) {	kfree(part->XferInfo);	part->XferInfo = NULL;    }    if (part->bam_cache) {	kfree(part->bam_cache);	part->bam_cache = NULL;    }    } /* ftl_freepart */static void ftl_notify_add(struct mtd_info *mtd){	partition_t *partition;	int device;	for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)		;	if (device == MAX_MTD_DEVICES) {		printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"		       "Not scanning <%s>\n", mtd->name);		return;	}	partition = kmalloc(sizeof(partition_t), GFP_KERNEL);			if (!partition) {		printk(KERN_WARNING "No memory to scan for FTL on %s\n",		       mtd->name);		return;	}    	memset(partition, 0, sizeof(partition_t));	partition->mtd = mtd;	if ((scan_header(partition) == 0) && 	    (build_maps(partition) == 0)) {				partition->state = FTL_FORMATTED;		atomic_set(&partition->open, 0);		myparts[device] = partition;		ftl_reread_partitions(device << 4);#ifdef PCMCIA_DEBUG		printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",		       le32_to_cpu(partition->header.FormattedSize) >> 10);#endif	} else		kfree(partition);}static void ftl_notify_remove(struct mtd_info *mtd){        int i,j;	/* Q: What happens if you try to remove a device which has	 *    a currently-open FTL partition on it?	 *	 * A: You don't. The ftl_open routine is responsible for	 *    increasing the use count of the driver module which	 *    it uses.	 */	/* That's the theory, anyway :) */	for (i=0; i< MAX_MTD_DEVICES; i++)		if (myparts[i] && myparts[i]->mtd == mtd) {			if (myparts[i]->state == FTL_FORMATTED)				ftl_freepart(myparts[i]);						myparts[i]->state = 0;			for (j=0; j<16; j++) {				ftl_gendisk.part[j].nr_sects=0;				ftl_gendisk.part[j].start_sect=0;			}			kfree(myparts[i]);			myparts[i] = NULL;		}}int init_ftl(void){    int i;    memset(myparts, 0, sizeof(myparts));        DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n");        if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {	printk(KERN_NOTICE "ftl_cs: unable to grab major "	       "device number!\n");	return -EAGAIN;    }        for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)	ftl_blocksizes[i] = 1024;    for (i = 0; i < MAX_DEV*MAX_PART; i++) {	ftl_hd[i].nr_sects = 0;	ftl_hd[i].start_sect = 0;    }    blksize_size[FTL_MAJOR] = ftl_blocksizes;    ftl_gendisk.major = FTL_MAJOR;    blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);    add_gendisk(&ftl_gendisk);        register_mtd_user(&ftl_notifier);        return 0;}static void __exit cleanup_ftl(void){    unregister_mtd_user(&ftl_notifier);    unregister_blkdev(FTL_MAJOR, "ftl");    blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));    blksize_size[FTL_MAJOR] = NULL;    del_gendisk(&ftl_gendisk);}module_init(init_ftl);module_exit(cleanup_ftl);MODULE_LICENSE("Dual MPL/GPL");MODULE_AUTHOR("David Hinds <dhinds@sonic.net>");MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");

⌨️ 快捷键说明

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