📄 mtdblock.c
字号:
mtdblks[dev] = mtdblk; mtd_sizes[dev] = mtdblk->mtd->size/1024; mtd_blksizes[dev] = mtdblk->mtd->erasesize; if (mtd_blksizes[dev] > PAGE_SIZE) mtd_blksizes[dev] = PAGE_SIZE; set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE)); spin_unlock(&mtdblks_lock); DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0;}static release_t mtdblock_release(struct inode *inode, struct file *file){ int dev; struct mtdblk_dev *mtdblk;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) struct super_block * sb = get_super(inode->i_rdev);#endif DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); if (inode == NULL) release_return(-ENODEV); fsync_dev(inode->i_rdev);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if (sb) invalidate_inodes(sb);#endif invalidate_buffers(inode->i_rdev); dev = MINOR(inode->i_rdev); mtdblk = mtdblks[dev]; down(&mtdblk->cache_sem); write_cached_data(mtdblk); up(&mtdblk->cache_sem); spin_lock(&mtdblks_lock); if (!--mtdblk->count) { /* It was the last usage. Free the device */ mtdblks[dev] = NULL; spin_unlock(&mtdblks_lock); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); put_mtd_device(mtdblk->mtd); vfree(mtdblk->cache_data); kfree(mtdblk); } else { spin_unlock(&mtdblks_lock); } DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); MOD_DEC_USE_COUNT; release_return(0);} /* * This is a special request_fn because it is executed in a process context * to be able to sleep independently of the caller. The io_request_lock * is held upon entry and exit. * The head of our request queue is considered active so there is no need * to dequeue requests before we are done. */static void handle_mtdblock_request(void){ struct request *req; struct mtdblk_dev *mtdblk; unsigned int res; for (;;) { INIT_REQUEST; req = CURRENT; spin_unlock_irq(&io_request_lock); mtdblk = mtdblks[MINOR(req->rq_dev)]; res = 0; if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES) panic(__FUNCTION__": minor out of bound"); if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9)) goto end_req; // Handle the request switch (req->cmd) { int err; case READ: down(&mtdblk->cache_sem); err = do_cached_read (mtdblk, req->sector << 9, req->current_nr_sectors << 9, req->buffer); up(&mtdblk->cache_sem); if (!err) res = 1; break; case WRITE: // Read only device if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) ) break; // Do the write down(&mtdblk->cache_sem); err = do_cached_write (mtdblk, req->sector << 9, req->current_nr_sectors << 9, req->buffer); up(&mtdblk->cache_sem); if (!err) res = 1; break; }end_req: spin_lock_irq(&io_request_lock); end_request(res); }}static volatile int leaving = 0;#if LINUX_VERSION_CODE > 0x020300static DECLARE_MUTEX_LOCKED(thread_sem);static DECLARE_WAIT_QUEUE_HEAD(thr_wq);#elsestatic struct semaphore thread_sem = MUTEX_LOCKED;DECLARE_WAIT_QUEUE_HEAD(thr_wq);#endifint mtdblock_thread(void *dummy){ struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); tsk->session = 1; tsk->pgrp = 1; /* we might get involved when memory gets low, so use PF_MEMALLOC */ tsk->flags |= PF_MEMALLOC; strcpy(tsk->comm, "mtdblockd"); tsk->tty = NULL; spin_lock_irq(&tsk->sigmask_lock); sigfillset(&tsk->blocked); recalc_sigpending(tsk); spin_unlock_irq(&tsk->sigmask_lock); exit_mm(tsk); exit_files(tsk); exit_sighand(tsk); exit_fs(tsk); while (!leaving) { add_wait_queue(&thr_wq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irq(&io_request_lock); if (QUEUE_EMPTY || QUEUE_PLUGGED) { spin_unlock_irq(&io_request_lock); schedule(); remove_wait_queue(&thr_wq, &wait); } else { remove_wait_queue(&thr_wq, &wait); set_current_state(TASK_RUNNING); handle_mtdblock_request(); spin_unlock_irq(&io_request_lock); } } up(&thread_sem); return 0;}#if LINUX_VERSION_CODE < 0x20300#define RQFUNC_ARG void#else#define RQFUNC_ARG request_queue_t *q#endifstatic void mtdblock_request(RQFUNC_ARG){ /* Don't do anything, except wake the thread if necessary */ wake_up(&thr_wq);}static int mtdblock_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){ struct mtdblk_dev *mtdblk; mtdblk = mtdblks[MINOR(inode->i_rdev)];#ifdef PARANOIA if (!mtdblk) BUG();#endif switch (cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) return -EFAULT; return put_user((mtdblk->mtd->size >> 9), (long *) arg)?-EFAULT:0; 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); down(&mtdblk->cache_sem); write_cached_data(mtdblk); up(&mtdblk->cache_sem); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); return 0; default: return -EINVAL; }}#if LINUX_VERSION_CODE < 0x20326static struct file_operations mtd_fops ={ open: mtdblock_open, ioctl: mtdblock_ioctl, release: mtdblock_release, read: block_read, write: block_write};#elsestatic struct block_device_operations mtd_fops = { open: mtdblock_open, release: mtdblock_release, ioctl: mtdblock_ioctl};#endif#ifdef CONFIG_DEVFS_FS/* Notification that a new device has been added. Create the devfs entry for * it. */static void mtd_notify_add(struct mtd_info* mtd){ char name[8]; if (!mtd) 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, &mtd_fops, NULL);}static void mtd_notify_remove(struct mtd_info* mtd){ if (!mtd) return; devfs_unregister(devfs_rw_handle[mtd->index]);}#endif#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)#define init_mtdblock init_module#define cleanup_mtdblock cleanup_module#endifint __init init_mtdblock(void){ int i; spin_lock_init(&mtdblks_lock);#ifdef CONFIG_DEVFS_FS if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops)) { 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,&mtd_fops)) { 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++) { mtd_sizes[i] = 0; mtd_blksizes[i] = BLOCK_SIZE; } init_waitqueue_head(&thr_wq); /* Allow the block size to default to BLOCK_SIZE. */ blksize_size[MAJOR_NR] = mtd_blksizes; blk_size[MAJOR_NR] = mtd_sizes; #if LINUX_VERSION_CODE < 0x20320 blk_dev[MAJOR_NR].request_fn = mtdblock_request;#else blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);#endif kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND); return 0;}static void __exit cleanup_mtdblock(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#if LINUX_VERSION_CODE < 0x20320 blk_dev[MAJOR_NR].request_fn = NULL;#else blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));#endif blksize_size[MAJOR_NR] = NULL; blk_size[MAJOR_NR] = NULL;}module_init(init_mtdblock);module_exit(cleanup_mtdblock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -