Linux字符设备驱动开发框架

11 篇文章 0 订阅

仅供参考

 

#include <linux/moducle.h>
#include <linux/types.h>
#include <fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uacccess.h>

#define VIRTUALDISK_SIZE	0x2000 	//size =8K
#define MEM_CLEAR			0x1
#define PORT1_SET			0x1
#define PORT2_SET			0x2
#define VIRTUALDISK_MAJOR 	200		//virtualDisk major device port = 200

#define MINORBITS			20	
#define MINORMASK			((1U <<MINORBITS) -1 )
#define MAJOR(dev)			((unsigned int )((dev)>>MINORBITS))
#define MINOR(dev)			((unsigned int)((dev)&MINORMASK))	

static int VirtualDisk_major = VIRTUALDISK_MAJOR;

struct VirtualDisk
{
	struct cdev cdev;
	unsigned char mem[VIRTUALDISK_SIZE];
	int port1;
	long port2;
	long count;		//recort the number of device is opening
};



int VirtualDisk_init(void)
{
	int result;
	dev_t devno = MKDEV(VirtualDisk_major,0); //build the device number

	// apply the device number
	if(VirtualDisk_major)
	{
		result = register_chrdev_region(&devno, 1, "VirtualDisk"); //if not 0, static apply
	}
	else
	{
		result = alloc_chrdev_region(&devno,0, 1, "VirtualDisk"); //auto 
		VirtualDisk_major = MAJOR(devno);
	}

	if(result < 0)
	{
		return result;
	}

	cdev  Virtualdisk_devp = kmalloc(sizeof(struct VirtualDisk), GFP_KERNEL);
	if(! Virtualdisk_devp)
	{
		result = -ENOMEM;
		goto fail_kmalloc;
	}

	memset(Virtualdisk_devp, 0, sizeof(struct VirtualDisk));
	VitualDisk_setup_cdev(Virtualdisk_devp, 0);
	return 0;

	fail_kmalloc:
		unregister_chrdev_region(devno, 1);

	return result;
}



//module rmmod

void VirtualDisk_exit(void)
{
	cdev_del(&Virtualdisk_devp->cdev);
	kfree(Virtualdisk_devp);
	unregister_chrdev_region(MKDEV(VirtualDisk_major,0),1);
}



static void VirtualDisk_setup_cdev(struct VirtualDisk *dev, int minor)
{
	int err;
	devno	= MKDEV(VirtualDisk_major,minor);
	cdev_init(&dev->cdev, &VirtualDisk_fops);
	dev-cdev.ower = THIS_MODULE;
	dev->cdev.ops = &VirtualDisk_fops;

	err = cdev_add(&dev->cdev, devno, 1);
	if(err)
	{
		printk(KERN_NOTICE "Error in cdev_add()\n");
	}
}


static const struct file_operations VirtualDisk_fops = 
{
	.owner = THIS_MODULE,
	.llseek	= VirtualDisk_llseek,
	.read 	= VirtualDisk_read,
	.write	= VirtualDisk_write,
	.ioctl	= VirtualDisk_ioctl,
	.open 	= VirtualDisk_open,
	.release= VirtualDisk_release,
}


int VirtualDisk_open(struct inode *inode, struct file *filep)
{
	filep->private_data = VirtualDisk_devp;
	struct VirtualDisk *devp = filep->private_data;
	devp->count++;
	return 0;
}

int VirtualDisk_release(struct inode *inode, struct file *filep)
{
	struct VirtualDisk *devp = filep->private_data;
	devp->count--;
	return 0;
}



static ssize_t VirtualDisk_read(struct file *filep, char __user *buf, size_t size, loff_t *ppos)
{
	unsigned long p = *ppos;
	unsigned int count = size;
	int ret = 0;

	struct VirtualDisk* devp = filep->private_data;
	if(p >= VIRTUALDISK_SIZE)
	{
		return count?-ENXIO:0;
	}

	if(count > VIRTUALDISK_SIZE -p )
	{
		count = VIRTUALDISK_SIZE -p;
	}

	if(copy_to_user(buf, (void*)(devp->mem+p), count))
	{
		ret = -EFAULT;
	}
	else
	{
		*ppos +=count;
		return = count;
		printk(KERN_INFO "read %d bytes(s) from %d \n", count ,p);
	}

	return ret;
}



static ssize_t VirtualDisk_write (struct file *filep, const char __user *buf, size_t size  , loff_t *ppos)
{
	unsigned long p = *ppos;
	int ret =0;
	unsigned int count = size;

	struct VirtualDisk *devp = filep->private_data;

	if(p >= VIRTUALDISK_SIZE)
	{
		return count? -ENXIO:0;
	}

	if(count > VIRTUALDISK_SIZE - p)
	{
		retu  VIRTUALDISK_SIZE - p ;
	}

	if(copy_from_user(devp->mem + p, buf, count))
	{
		return -EFAULT;
	}
	else
	{
		*ppos += count;
		ret = count;
		printk (KERN_INFO "written %d bytes(s) from %d\n", count ,p);
	}

	return ret;
}


static loff_t VirtualDisk_llseek(struct file *filep, loff_t offset ,int orig)
{
	switch (orig)
	{
		case SEEK_SET:
		if(offset < 0)
		{
			ret = -EINVAL;
			break;
		}
		if((unsigned int )offset > VIRTUALDISK_SIZE)
		{
			ret = - EINVAL;
			break;
		}

		filep->f_pos = (unsigned int )offset;
		ret = filep->f_pos;
		break;

		case SEEK_CUR:
		if((filep->f_pos + offset)>VIRTUALDISK_SIZE)
		{
			ret = -EINVAL;
			break;
		}
		if((filep->f_pos) + offset < 0)
		{
			ret = -EINVAL;
			break;
		}

		filep->f_pos += offset;
		ret = filep->f_pos;
		break;

		default:
		ret = -EINVAL;
		break;

	}

	return ret;
}



static int VirtualDisk_ioctl(struct inode *inodep, struct file* filep, unsigned int cmd, unsigned long arg)
{
	struct VirtualDisk*devp = filep->private_data;

	switch(cmd)
	{
		case EM_CLEAR:
		memset(devp->mem, 0 , VIRTUALDISK_SIZE);
		printk(KERN_INFO "VirtualDisk is set to zero \n");
		break;

		case PORT1_SET:
		devp->port1 = 0;
		break;

		case PORT2_SET:
		devp->port2 = 0;
		break;

		default:
		return -EINVAL;
	}

	return 0;

}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值