From: Adrian M. <zx8...@us...> - 2002-09-14 23:50:35
|
Update of /cvsroot/linuxdc/linux-sh-dc/fs In directory usw-pr-cvs1:/tmp/cvs-serv2915/fs Added Files: vmuflash-fs.c Log Message: initial check-in of vmu flash filesystem driver --- NEW FILE: vmuflash-fs.c --- /* * * * VMU Flash File System Driver for LinuxDC * http://sourceforge.net/projects/linuxdc * * Copyright, Adrian McMenamin, 2002 * ad...@mc... * * Licenced under version 2 of the * Free Software Foundation's * General Public Licence * http://www.gnu.org * * Much of this driver is based * on existing mtd block drivers. * All copyrights acknowledged. * * */ #define VMUFS_DEBUG #define CONFIG_DEVFS_FS #include <linux/config.h> #include <linux/types.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/fs.h> #include <linux/blkdev.h> #define DEVICE_NAME "vmufs" #define DEVICE_NR(device) (device) #define MAJOR_NR MTD_BLOCK_MAJOR #include <linux/blk.h> #ifdef CONFIG_DEVFS_FS #include <linux/devfs_fs_kernel.h> static void vmufs_notify_add(struct mtd_info* mtd); static void vmufs_notify_remove(struct mtd_info* mtd); static struct mtd_notifier notifier = { vmufs_notify_add, vmufs_notify_remove, NULL }; static devfs_handle_t devfs_dir_handle = NULL; static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES]; #endif static spinlock_t vmublks_lock; static int vmublk_size[MAX_MTD_DEVICES]; static int vmublksize_size[MAX_MTD_DEVICES]; static struct vmublk_dev { struct mtd_info *mtd; /* Locked */ int count; } *vmublks[MAX_MTD_DEVICES]; static struct block_device_operations vmufs_bdops; #ifdef CONFIG_DEVFS_FS /* Notification that a new device has been added. Create the devfs entry for * it. */ static void vmufs_notify_add(struct mtd_info* mtd) { char name[8]; if (!mtd || mtd->type == MTD_ABSENT) return; sprintf(name, "%d", mtd->index); devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name, DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index, S_IFBLK | S_IRUGO | S_IWUGO, &vmufs_bdops, NULL); } static void vmufs_notify_remove(struct mtd_info* mtd) { if (!mtd || mtd->type == MTD_ABSENT) return; devfs_unregister(devfs_rw_handle[mtd->index]); } #endif /******************************************** * Define the block operations for the vmufs* ********************************************/ int vmufs_open(struct inode *inode, struct file *filp) { struct vmublk_dev *vmublk; struct mtd_info *mtd; int dev; DEBUG(MTD_DEBUG_LEVEL1,"vmuflash_fs_open\n"); if (!inode) return -EINVAL; dev = MINOR(inode->i_rdev); if (dev >= MAX_MTD_DEVICES) return -EINVAL; mtd = get_mtd_device(NULL, dev); if (!mtd) return -ENODEV; if (MTD_ABSENT == mtd->type) { put_mtd_device(mtd); return -ENODEV; } spin_lock(&vmublks_lock); /* If it's already open.... */ if (vmublks[dev]) { vmublks[dev]->count++; spin_unlock(&vmublks_lock); return 0; } /* OK, it's not open. Try to find it */ /* First we have to drop the lock, because we have to to things which might sleep. */ spin_unlock(&vmublks_lock); vmublk = kmalloc(sizeof(struct vmublk_dev), GFP_KERNEL); if (!vmublk) { put_mtd_device(mtd); return -ENOMEM; } memset(vmublk, 0, sizeof(*vmublk)); vmublk->count = 1; vmublk->mtd = mtd; /* OK, we've created a new one. Add it to the list. */ spin_lock(&vmublks_lock); vmublks[dev] = vmublk; vmublk_size[dev] = vmublk->mtd->size/1024; if (vmublk->mtd->erasesize) vmublksize_size[dev] = vmublk->mtd->erasesize; if (vmublksize_size[dev] > PAGE_SIZE) vmublksize_size[dev] = PAGE_SIZE; set_device_ro (inode->i_rdev, !(vmublk->mtd->flags & MTD_WRITEABLE)); spin_unlock(&vmublks_lock); DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; } int vmufs_release(struct inode *inode, struct file *filp) { return 1; } int vmufs_ioctl(struct inode *inode, struct file *filp, unsigned int command, unsigned long argument) { return 1; } int vmufs_check_change(kdev_t dev) { return 1; } int vmufs_revalidate(kdev_t dev) { return 1; } static int get_vmu_device(const struct request *req) { int devno; devno = MINOR(req->rq_dev); /* Is there an mtd device for this? */ struct mtd_info *mtd = get_mtd_device(NULL, devno); if (!mtd){ static int count = 0; if (count++ < 45) /* TO DO: Lower this for production driver */ printk(KERN_WARNING "vmufs: requested an unknown device: %i\n", devno); return -1; } put_mtd_device(mtd); return devno; } static int vmufs_transfer(int devno, const struct request *req) { struct mtd_info *mtd = get_mtd_device(NULL, devno); int size, retsize, retvalue = 1; u8 *ptr = NULL; size = req->current_nr_sectors * mtd->erasesize; switch(req->cmd){ case READ: ptr = kmalloc(size, GFP_KERNEL); if (((mtd->read)(mtd, req->sector * mtd->erasesize, size, &retsize, ptr)) < 0){ /* Failed */ retvalue = -1; static int count = 0; if (count++ < 45) /* TO DO: Lower this for production driver */ printk(KERN_WARNING "vmufs: failed on read\n"); break; } memcpy(req->buffer, ptr, retsize); break; case WRITE: ptr = kmalloc(size, GFP_KERNEL); memcpy(ptr, req->buffer, size); if (((mtd->write)(mtd, req->sector * mtd->erasesize, size, &retsize, ptr)) < 0){ /* Failed */ retvalue = -1; static int count = 0; if (count++ < 45) /* TO DO: Lower this for production driver */ printk(KERN_WARNING "vmufs: failed on write\n"); break; } default: retvalue = 0; } if (ptr) kfree(ptr); put_mtd_device(mtd); return retvalue; } void vmufs_request(request_queue_t *q) { int device, status; while (1){ INIT_REQUEST; /* Check we have a real device */ device = get_vmu_device(CURRENT); if (device < 0){ end_request(0); continue; } status = vmufs_transfer(device, CURRENT); printk("request %p: cmd %i sec %li (nr. %li)\n", CURRENT, CURRENT->cmd, CURRENT->sector, CURRENT->current_nr_sectors); end_request(1); } } int __init init_vmufs(void) { int i; spin_lock_init(&vmufs_lock); #ifdef CONFIG_DEVFS_FS if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &vmufs_bdops)) { printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", MTD_BLOCK_MAJOR); return -EAGAIN; } devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL); register_mtd_user(¬ifier); #else if (register_blkdev(MAJOR_NR,DEVICE_NAME,&vmufs_bdops)) { printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", MTD_BLOCK_MAJOR); return -EAGAIN; } #endif /* We fill it in at open() time. */ for (i=0; i< MAX_MTD_DEVICES; i++) { vmublk_size[i] = 0; vmublksize_size[i] = 0; /* Not fixed (in theory) for DC vmu flash */ } /* init_waitqueue_head(&vmufs_wq); */ blksize_size[MAJOR_NR] = vmublksize_size; blk_size[MAJOR_NR] = vmublk_size; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &vmufs_request); /*kernel_thread (vmufs_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND); */ /* Do I need this? */ return 0; } static void __exit exit_vmufs(void) { /* leaving = 1; wake_up(&thr_wq); down(&thread_sem); */ #ifdef CONFIG_DEVFS_FS unregister_mtd_user(¬ifier); devfs_unregister(devfs_dir_handle); devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME); #else unregister_blkdev(MAJOR_NR,DEVICE_NAME); #endif blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); blksize_size[MAJOR_NR] = NULL; blk_size[MAJOR_NR] = NULL; } static struct block_device_operations vmufs_bdops = { open: vmufs_open, release: vmufs_release, ioctl: vmufs_ioctl, check_media_change: vmufs_check_change, revalidate: vmufs_revalidate, }; module_init(init_vmufs); module_exit(exit_vmufs); MODULE_DESCRIPTION("VMUFS - Dreamcast VMU File System"); MODULE_AUTHOR("Adrian McMenamin"); MODULE_LICENSE("GPL"); |