Linux驱动下的字符设备基本模板(未使用设备树)
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include<linux/cdev.h>
#include<linux/device.h>
#define LED_MAJOR 200
#define LED_NAME "led"
#define NEWCHRLED_NAME "newchrled"
#define NEWCHRLED_COUNT 1
#define LEDOFF 0 //关闭
#define LEDON 1 //打开
//设备结构体
struct newchrled_dev
{
struct cdev cdev; //字符设备
dev_t devid; //设备号
struct class * class; //类
struct device * device; //设备
int major;
int minor;
};
struct newchrled_dev newchrled; //led设备
static int newchrled_open(struct inode *inode, struct file *filp)
{
filp->private_data = &newchrled;
return 0;
}
static ssize_t newchrled_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
static int newchrled_release(struct inode *inode, struct file *filp)
{
struct newchrled_dev *dev = (struct newchrled_dev *)filp->private_data;
return 0;
}
static const struct file_operations newchrled_fops=
{
.owner = THIS_MODULE,
.write = newchrled_write,
.open = newchrled_open,
.release = newchrled_release,
};
//入口
static int __init newchrled_init(void)
{
int ret;
//2、分配设备号
newchrled.major = 0; //表示由系统申请设备号
if(newchrled.major)
{
newchrled.devid = MKDEV(newchrled.major,0);
ret = register_chrdev_region(newchrled.devid,NEWCHRLED_COUNT,NEWCHRLED_NAME);
}
else
{
ret = alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_COUNT,NEWCHRLED_NAME);
newchrled.major = MAJOR(newchrled.devid);
newchrled.minor = MINOR(newchrled.devid);
}
if(ret < 0)
{
printk("newchrled chrdev_region err!\r\n");
goto fail_devid;
}
printk("newchrled major = %d,minor = %d\r\n",newchrled.major,newchrled.minor);
//3、注册字符设备
newchrled.cdev.owner = THIS_MODULE;
cdev_init(&newchrled.cdev,&newchrled_fops);
ret = cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_COUNT);
if(ret < 0)
goto fail_cdev;
//4、自动创建设备节点
newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
if (IS_ERR(newchrled.class))
{
ret = PTR_ERR(newchrled.class);
goto fail_class;
}
newchrled.device = device_create(newchrled.class, NULL, newchrled.devid, NULL, NEWCHRLED_NAME);
if (IS_ERR(newchrled.device))
{
ret = PTR_ERR(newchrled.device);
goto fail_device;
}
return 0;
fail_device:
class_destroy(newchrled.class);
fail_class:
cdev_del(&newchrled.cdev);
fail_cdev:
unregister_chrdev_region(newchrled.devid, NEWCHRLED_COUNT);
fail_devid:
return ret;
}
static void __exit newchrled_exit(void)
{
//删除字符设备
cdev_del(&newchrled.cdev);
//1、注销设备号
unregister_chrdev_region(newchrled.devid, NEWCHRLED_COUNT);
//设备摧毁
device_destroy(newchrled.class, newchrled.devid);
//类的删除
class_destroy(newchrled.class);
}
//注册和卸载驱动
module_init(newchrled_init);
module_exit(newchrled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wzh");