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

📄 mtdchar.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		struct region_info_user *ur = (struct region_info_user *) argp;		if (get_user(ur_idx, &(ur->regionindex)))			return -EFAULT;		kr = &(mtd->eraseregions[ur_idx]);		if (put_user(kr->offset, &(ur->offset))		    || put_user(kr->erasesize, &(ur->erasesize))		    || put_user(kr->numblocks, &(ur->numblocks)))			return -EFAULT;		break;	}	case MEMGETINFO:		info.type	= mtd->type;		info.flags	= mtd->flags;		info.size	= mtd->size;		info.erasesize	= mtd->erasesize;		info.writesize	= mtd->writesize;		info.oobsize	= mtd->oobsize;		/* The below fields are obsolete */		info.ecctype	= -1;		info.eccsize	= 0;		if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))			return -EFAULT;		break;	case MEMERASE:	{		struct erase_info *erase;		if(!(file->f_mode & FMODE_WRITE))			return -EPERM;		erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);		if (!erase)			ret = -ENOMEM;		else {			wait_queue_head_t waitq;			DECLARE_WAITQUEUE(wait, current);			init_waitqueue_head(&waitq);			if (copy_from_user(&erase->addr, argp,				    sizeof(struct erase_info_user))) {				kfree(erase);				return -EFAULT;			}			erase->mtd = mtd;			erase->callback = mtdchar_erase_callback;			erase->priv = (unsigned long)&waitq;			/*			  FIXME: Allow INTERRUPTIBLE. Which means			  not having the wait_queue head on the stack.			  If the wq_head is on the stack, and we			  leave because we got interrupted, then the			  wq_head is no longer there when the			  callback routine tries to wake us up.			*/			ret = mtd->erase(mtd, erase);			if (!ret) {				set_current_state(TASK_UNINTERRUPTIBLE);				add_wait_queue(&waitq, &wait);				if (erase->state != MTD_ERASE_DONE &&				    erase->state != MTD_ERASE_FAILED)					schedule();				remove_wait_queue(&waitq, &wait);				set_current_state(TASK_RUNNING);				ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0;			}			kfree(erase);		}		break;	}	case MEMWRITEOOB:	{		struct mtd_oob_buf buf;		struct mtd_oob_ops ops;		struct mtd_oob_buf __user *user_buf = argp;	        uint32_t retlen;		if(!(file->f_mode & FMODE_WRITE))			return -EPERM;		if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))			return -EFAULT;		if (buf.length > 4096)			return -EINVAL;		if (!mtd->write_oob)			ret = -EOPNOTSUPP;		else			ret = access_ok(VERIFY_READ, buf.ptr,					buf.length) ? 0 : EFAULT;		if (ret)			return ret;		ops.ooblen = buf.length;		ops.ooboffs = buf.start & (mtd->oobsize - 1);		ops.datbuf = NULL;		ops.mode = MTD_OOB_PLACE;		if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))			return -EINVAL;		ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);		if (!ops.oobbuf)			return -ENOMEM;		if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) {			kfree(ops.oobbuf);			return -EFAULT;		}		buf.start &= ~(mtd->oobsize - 1);		ret = mtd->write_oob(mtd, buf.start, &ops);		if (ops.oobretlen > 0xFFFFFFFFU)			ret = -EOVERFLOW;		retlen = ops.oobretlen;		if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length)))			ret = -EFAULT;		kfree(ops.oobbuf);		break;	}	case MEMREADOOB:	{		struct mtd_oob_buf buf;		struct mtd_oob_ops ops;		if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))			return -EFAULT;		if (buf.length > 4096)			return -EINVAL;		if (!mtd->read_oob)			ret = -EOPNOTSUPP;		else			ret = access_ok(VERIFY_WRITE, buf.ptr,					buf.length) ? 0 : -EFAULT;		if (ret)			return ret;		ops.ooblen = buf.length;		ops.ooboffs = buf.start & (mtd->oobsize - 1);		ops.datbuf = NULL;		ops.mode = MTD_OOB_PLACE;		if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))			return -EINVAL;		ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);		if (!ops.oobbuf)			return -ENOMEM;		buf.start &= ~(mtd->oobsize - 1);		ret = mtd->read_oob(mtd, buf.start, &ops);		if (put_user(ops.oobretlen, (uint32_t __user *)argp))			ret = -EFAULT;		else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf,						    ops.oobretlen))			ret = -EFAULT;		kfree(ops.oobbuf);		break;	}	case MEMLOCK:	{		struct erase_info_user einfo;		if (copy_from_user(&einfo, argp, sizeof(einfo)))			return -EFAULT;		if (!mtd->lock)			ret = -EOPNOTSUPP;		else			ret = mtd->lock(mtd, einfo.start, einfo.length);		break;	}	case MEMUNLOCK:	{		struct erase_info_user einfo;		if (copy_from_user(&einfo, argp, sizeof(einfo)))			return -EFAULT;		if (!mtd->unlock)			ret = -EOPNOTSUPP;		else			ret = mtd->unlock(mtd, einfo.start, einfo.length);		break;	}	/* Legacy interface */	case MEMGETOOBSEL:	{		struct nand_oobinfo oi;		if (!mtd->ecclayout)			return -EOPNOTSUPP;		if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))			return -EINVAL;		oi.useecc = MTD_NANDECC_AUTOPLACE;		memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));		memcpy(&oi.oobfree, mtd->ecclayout->oobfree,		       sizeof(oi.oobfree));		oi.eccbytes = mtd->ecclayout->eccbytes;		if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))			return -EFAULT;		break;	}	case MEMGETBADBLOCK:	{		loff_t offs;		if (copy_from_user(&offs, argp, sizeof(loff_t)))			return -EFAULT;		if (!mtd->block_isbad)			ret = -EOPNOTSUPP;		else			return mtd->block_isbad(mtd, offs);		break;	}	case MEMSETBADBLOCK:	{		loff_t offs;		if (copy_from_user(&offs, argp, sizeof(loff_t)))			return -EFAULT;		if (!mtd->block_markbad)			ret = -EOPNOTSUPP;		else			return mtd->block_markbad(mtd, offs);		break;	}#ifdef CONFIG_HAVE_MTD_OTP	case OTPSELECT:	{		int mode;		if (copy_from_user(&mode, argp, sizeof(int)))			return -EFAULT;		mfi->mode = MTD_MODE_NORMAL;		ret = otp_select_filemode(mfi, mode);		file->f_pos = 0;		break;	}	case OTPGETREGIONCOUNT:	case OTPGETREGIONINFO:	{		struct otp_info *buf = kmalloc(4096, GFP_KERNEL);		if (!buf)			return -ENOMEM;		ret = -EOPNOTSUPP;		switch (mfi->mode) {		case MTD_MODE_OTP_FACTORY:			if (mtd->get_fact_prot_info)				ret = mtd->get_fact_prot_info(mtd, buf, 4096);			break;		case MTD_MODE_OTP_USER:			if (mtd->get_user_prot_info)				ret = mtd->get_user_prot_info(mtd, buf, 4096);			break;		default:			break;		}		if (ret >= 0) {			if (cmd == OTPGETREGIONCOUNT) {				int nbr = ret / sizeof(struct otp_info);				ret = copy_to_user(argp, &nbr, sizeof(int));			} else				ret = copy_to_user(argp, buf, ret);			if (ret)				ret = -EFAULT;		}		kfree(buf);		break;	}	case OTPLOCK:	{		struct otp_info oinfo;		if (mfi->mode != MTD_MODE_OTP_USER)			return -EINVAL;		if (copy_from_user(&oinfo, argp, sizeof(oinfo)))			return -EFAULT;		if (!mtd->lock_user_prot_reg)			return -EOPNOTSUPP;		ret = mtd->lock_user_prot_reg(mtd, oinfo.start, oinfo.length);		break;	}#endif	case ECCGETLAYOUT:	{		if (!mtd->ecclayout)			return -EOPNOTSUPP;		if (copy_to_user(argp, mtd->ecclayout,				 sizeof(struct nand_ecclayout)))			return -EFAULT;		break;	}	case ECCGETSTATS:	{		if (copy_to_user(argp, &mtd->ecc_stats,				 sizeof(struct mtd_ecc_stats)))			return -EFAULT;		break;	}	case MTDFILEMODE:	{		mfi->mode = 0;		switch(arg) {		case MTD_MODE_OTP_FACTORY:		case MTD_MODE_OTP_USER:			ret = otp_select_filemode(mfi, arg);			break;		case MTD_MODE_RAW:			if (!mtd->read_oob || !mtd->write_oob)				return -EOPNOTSUPP;			mfi->mode = arg;		case MTD_MODE_NORMAL:			break;		default:			ret = -EINVAL;		}		file->f_pos = 0;		break;	}	default:		ret = -ENOTTY;	}	return ret;} /* memory_ioctl */static const struct file_operations mtd_fops = {	.owner		= THIS_MODULE,	.llseek		= mtd_lseek,	.read		= mtd_read,	.write		= mtd_write,	.ioctl		= mtd_ioctl,	.open		= mtd_open,	.release	= mtd_close,};static int __init init_mtdchar(void){	if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {		printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",		       MTD_CHAR_MAJOR);		return -EAGAIN;	}	mtd_class = class_create(THIS_MODULE, "mtd");	if (IS_ERR(mtd_class)) {		printk(KERN_ERR "Error creating mtd class.\n");		unregister_chrdev(MTD_CHAR_MAJOR, "mtd");		return PTR_ERR(mtd_class);	}	register_mtd_user(&notifier);	return 0;}static void __exit cleanup_mtdchar(void){	unregister_mtd_user(&notifier);	class_destroy(mtd_class);	unregister_chrdev(MTD_CHAR_MAJOR, "mtd");}module_init(init_mtdchar);module_exit(cleanup_mtdchar);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");MODULE_DESCRIPTION("Direct character-device access to MTD devices");

⌨️ 快捷键说明

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