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

📄 ftl_cs.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 3 页
字号:
    MOD_INC_USE_COUNT;    DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);    link = dev_table[DEVICE_NR(minor)];    if (!DEV_OK(link))	goto failed;    dev = (ftl_dev_t *)link->priv;    partition = &dev->minor[REGION_NR(minor)];    if (partition->region.RegionSize == 0)	goto failed;    while (partition->locked)	sleep_on(&ftl_wait_open);    if (partition->handle == NULL) {	partition->handle = (memory_handle_t)link->handle;	open.Attributes = partition->region.Attributes;	open.Offset = partition->region.CardOffset;	ret = CardServices(OpenMemory, &partition->handle, &open);	if (ret != CS_SUCCESS) {	    cs_error(OpenMemory, ret);	    goto failed;	}	if ((scan_header(partition) == 0) &&	    (build_maps(partition) == 0)) {	    partition->state = FTL_FORMATTED;	    ftl_reread_partitions(minor);#ifdef PCMCIA_DEBUG	    printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",		   partition->header.FormattedSize >> 10);#endif	} else {	    CardServices(CloseMemory, partition->handle);	    partition->handle = NULL;	    printk(KERN_NOTICE "ftl_cs: FTL partition is invalid.\n");	    goto failed;	}    }    partition->open++;    link->open++;    return 0;failed:    MOD_DEC_USE_COUNT;    return -ENODEV;} /* ftl_open *//*====================================================================*/static FS_RELEASE_T ftl_close(struct inode *inode, struct file *file){    dev_link_t *link;    int minor = MINOR(inode->i_rdev);    ftl_dev_t *dev;    partition_t *part;    int i;        DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);    /* Flush all writes */    fsync_dev(inode->i_rdev);    INVALIDATE_INODES(inode->i_rdev);    invalidate_buffers(inode->i_rdev);        link = dev_table[DEVICE_NR(minor)];    dev = (ftl_dev_t *)link->priv;    part = &dev->minor[REGION_NR(minor)];        /* Wait for any pending erase operations to complete */    for (i = 0; i < part->header.NumTransferUnits; i++) {	if (part->XferInfo[i].state == XFER_ERASING)	    sleep_on(&dev->erase_pending);	if (part->XferInfo[i].state == XFER_ERASED)	    prepare_xfer(part, i);    }        link->open--;    part->open--;    if (part->open == 0) {	CardServices(CloseMemory, part->handle);	part->handle = NULL;	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;	}    }        MOD_DEC_USE_COUNT;    return (FS_RELEASE_T)0;} /* ftl_close *//*======================================================================    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){    mem_op_t req;    u_int log_addr, bsize;    u_long i;    int ret;        DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",	  part->handle, sector, nblocks);    if (!(part->state & FTL_FORMATTED)) {	printk(KERN_NOTICE "ftl_cs: bad partition\n");	return -EIO;    }    bsize = part->region.BlockSize;    req.Attributes = MEM_OP_BUFFER_KERNEL;    req.Count = SECTOR_SIZE;    for (i = 0; i < nblocks; i++) {	if (((sector+i) * SECTOR_SIZE) >= 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 {	    req.Offset = (part->EUNInfo[log_addr / bsize].Offset			  + (log_addr % bsize));	    ret = CardServices(ReadMemory, part->handle, &req, buffer);	    if (ret != CS_SUCCESS) {		cs_error(ReadMemory, ret);		return -EIO;	    }	}	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_int log_addr,			 u_int virt_addr){    mem_op_t req;    u_int bsize, blk;#ifdef PSYCHO_DEBUG    u_int old_addr;#endif    u_short eun;    int ret;        DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",	  part->handle, log_addr, virt_addr);    bsize = part->region.BlockSize;    eun = log_addr / bsize;    blk = (log_addr % bsize) / SECTOR_SIZE;    req.Attributes = MEM_OP_BUFFER_KERNEL;    req.Count = sizeof(u_int);    req.Offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int) +		  part->header.BAMOffset);    #ifdef PSYCHO_DEBUG    CardServices(ReadMemory, part->handle, &req, &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 CS_GENERAL_FAILURE;    }#endif    if (part->bam_index == eun) {#ifdef PSYCHO_DEBUG	if (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, card = 0x%x\n",		       part->bam_cache[blk], old_addr);	    }	    return CS_GENERAL_FAILURE;	}#endif	part->bam_cache[blk] = virt_addr;    }    ret = CardServices(WriteMemory, part->handle, &req, &virt_addr);    if (ret != CS_SUCCESS) {	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);	cs_error(WriteMemory, ret);    }    return ret;} /* set_bam_entry */static int ftl_write(ftl_dev_t *dev, partition_t *part, caddr_t buffer,		     u_long sector, u_long nblocks){    mem_op_t req;    u_int bsize, log_addr, virt_addr, old_addr, blk;    u_long i;    int ret;    DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",	  part->handle, 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(dev, part);	if (ret != CS_SUCCESS)	    return ret;    }        bsize = part->region.BlockSize;    req.Attributes = MEM_OP_BUFFER_KERNEL;    req.Count = SECTOR_SIZE;    virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;    for (i = 0; i < nblocks; i++) {	if (virt_addr >= 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++;	req.Offset = (part->EUNInfo[part->bam_index].Offset +		      blk * SECTOR_SIZE);	ret = CardServices(WriteMemory, part->handle, &req, buffer);	if (ret != CS_SUCCESS) {	    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,		   req.Offset);	    cs_error(WriteMemory, ret);	    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) != CS_SUCCESS)		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);    dev_link_t *link;    ftl_dev_t *dev;    partition_t *part;    u_long sect;    link = dev_table[DEVICE_NR(minor)];    if (!DEV_OK(link)) return -ENODEV;    dev = (ftl_dev_t *)link->priv;    part = &dev->minor[REGION_NR(minor)];    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 = 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 = verify_area(VERIFY_WRITE, (long *)arg, sizeof(long));	if (ret) return ret;	put_user(ftl_hd[minor].nr_sects, (long *)arg);	break;    case BLKRRPART:	ret = ftl_reread_partitions(minor);	break;#if (LINUX_VERSION_CODE < VERSION(2,3,3))    case BLKFLSBUF:	if (!capable(CAP_SYS_ADMIN)) return -EACCES;	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){    int d = DEVICE_NR(minor), r = REGION_NR(minor);    ftl_dev_t *dev = dev_table[d]->priv;    partition_t *part = &(dev->minor[r]);    int i, whole;    DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);    if (part->locked || (part->open > 1))	return -EBUSY;    part->locked = 1;        whole = minor & ~(MAX_PART-1);    for (i = 0; i < MAX_PART; i++) {	if (ftl_hd[whole+i].nr_sects > 0) {	    kdev_t rdev = MKDEV(major_dev, whole+i);	    sync_dev(rdev);	    INVALIDATE_INODES(rdev);	    invalidate_buffers(rdev);	}	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, 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        part->locked = 0;    wake_up(&ftl_wait_open);    return 0;}/*======================================================================    Handler for block device requests======================================================================*/static void do_ftl_request(request_arg_t){    int ret, minor;    dev_link_t *link;    ftl_dev_t *dev;    partition_t *part;    DEBUG(2, "ftl_cs: starting do_ftl_request()\n");        do {	sti();	INIT_REQUEST;	minor = MINOR(CURRENT->rq_dev);		link = dev_table[DEVICE_NR(minor)];	dev = (ftl_dev_t *)link->priv;	part = &dev->minor[REGION_NR(minor)];	ret = 0;		switch (CURRENT->cmd) {	    	case READ:	    ret = ftl_read(part, CURRENT->buffer,			   CURRENT->sector+ftl_hd[minor].start_sect,			   CURRENT->current_nr_sectors);	    break;	    	case WRITE:	    ret = ftl_write(dev, part, CURRENT->buffer,			    CURRENT->sector+ftl_hd[minor].start_sect,			    CURRENT->current_nr_sectors);	    break;	    	default:	    panic("ftl_cs: unknown block command!\n");	    	}	end_request((ret == 0) ? 1 : 0);    } while (1);} /* do_ftl_request *//*====================================================================*/static int __init init_ftl_cs(void){    servinfo_t serv;    int i;        DEBUG(0, "%s\n", version);        CardServices(GetCardServicesInfo, &serv);    if (serv.Revision != CS_RELEASE_CODE) {	printk(KERN_NOTICE "ftl_cs: Card Services release "	       "does not match!\n");	return -EINVAL;    }        register_pccard_driver(&dev_info, &ftl_attach, &ftl_detach);    major_dev = register_blkdev(major_dev, "ftl", &ftl_blk_fops);    if (major_dev == 0) {	printk(KERN_NOTICE "ftl_cs: unable to grab major "	       "device number!\n");	return -ENODEV;    }    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[major_dev] = ftl_blocksizes;    ftl_gendisk.major = major_dev;    blk_init_queue(BLK_DEFAULT_QUEUE(major_dev), &do_ftl_request);    add_gendisk(&ftl_gendisk);    init_waitqueue_head(&ftl_wait_open);        return 0;}static void __exit exit_ftl_cs(void){    int i;    dev_link_t *link;    DEBUG(0, "ftl_cs: unloading\n");    unregister_pccard_driver(&dev_info);    if (major_dev != 0) {	unregister_blkdev(major_dev, "ftl");	blk_cleanup_queue(BLK_DEFAULT_QUEUE(major_dev));	blksize_size[major_dev] = NULL;    }    for (i = 0; i < MAX_DEV; i++) {	link = dev_table[i];	if (link) {	    if (link->state & DEV_CONFIG)		ftl_release((u_long)link);	    ftl_detach(link);	}    }    del_gendisk(&ftl_gendisk);}module_init(init_ftl_cs);module_exit(exit_ftl_cs);

⌨️ 快捷键说明

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