#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#define DEVICE_MEM_SIZE 20;
#define DEVICE_NAME "xxxxxx";//设备名称
#define DEVICE_COUNT 1;//设备数量
static int xxx_major = 250; //主设备号
static int xxx_minor = 0; //次设备号
static dev_t dev_number;
static struct class *xxx_class = NULL;
static unsigned char mem[DEVICE_MEM_SIZE];
struct cdev xxx_cdev;
static long xxx_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
switch(cmd)
{
case 0:
break;
case 1:
break;
default:
return -EINVAL;
}
return 0;
}
static int xxx_open(struct inode *inodep, struct file * filep) // 打开设备
{
printk("%s,%d\n", __func__, __LINE__);
return 0;
}
static int xxx_release(struct inode * inodep, struct file * filep) // 关闭设备
{
printk("%s,%d\n", __func__, __LINE__);
return 0;
}
static ssize_t xxx_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos)
{
//读取数据到用户空间
if(copy_to_user(buf,mem,count))
{
ret= -EFAULT;
printk("copyfrom user failed\n");
}
else{
ret= count;
printk("read%d bytes from dev\n", count);
}
return ret;
}
static ssize_t xxx_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)//注意:第二个参数和read方法不同
{
if(copy_from_user(mem,buf,count))
{
ret= -EFAULT;
printk("copyfrom user failed\n");
}
else{
ret= count;
printk("write%d bytes to dev\n", count);
}
return ret;
}
struct file_operations fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = xxx_ioctl,
.open = xxx_open,
.release = xxx_release,
.read = xxx_read,
.write = xxx_write,
};
static int __init xxx_init(void)
{
int ret = 0;
printk("%s,%d\n", __func__, __LINE__);
//cdev_init()函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接
cdev_init(&xxx_cdev, &dev_fops);
xxx_cdev.owner = THIS_MODULE;
/**在调用 cdev_add()函数向系统注册字符设备之前,
*应首先调用 register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号
**/
if (xxx_major)//静态申请
{
//使用下列宏则可以通过主设备号和次设备号生成 dev_t
dev_number = MKDEV(xxx_major, xxx_minor);
ret = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);
}
else //动态分配
{
ret = alloc_chrdev_region(&xxx_cdev.dev, 10, DEVICE_COUNT, DEVICE_NAME);
xxx_major = MAJOR(xxx_cdev.dev);
xxx_minor = MINOR(xxx_cdev.dev);
dev_number = xxx_cdev.dev;
}
if(ret)
{
printk("Failed to register_chrdev_region.\n");
return ret;
}
//系统添加一个 cdev,完成字符设备的注册。
ret = cdev_add(&xxx_cdev, dev_number, DEVICE_COUNT);
if(ret)
{
printk(KERN_NOTICE " Failed to cdev_add [Error] %d adding xxx%d", ret, DEVICE_COUNT);
unregister_chrdev_region(dev_number, DEVICE_NAME);
return ret;
}
xxx_class = class_create(THIS_MODULE,DEVICE_NAME);
device_create(xxx_class,NULL,dev_number,NULL,DEVICE_NAME);
return 0;
}
static void __exit xxx_exit(void)
{
printk("%s,%d\n", __func__, __LINE__);
//删除一个 cdev,完成字符设备的注销。
cdev_del(&xxx_cdev);
//在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号
unregister_chrdev_region(dev_number, DEVICE_COUNT);
}
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_AUTHOR(" lazybeee");
MODULE_LICENSE("GPL");