#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#define DEVICE_NAME "mydevice"
#define CLASS_NAME "myclass"
static int major_number;
static struct class *my_class = NULL;
static struct device *my_device = NULL;
static struct cdev my_cdev;
static int my_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device opened\n");
return 0;
}
static int my_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device closed\n");
return 0;
}
static ssize_t my_read(struct file *file, char __user *buf,
size_t len, loff_t *offset)
{
char data[] = "Hello from kernel!\n";
size_t datalen = strlen(data);
if (*offset >= datalen)
return 0;
if (len > datalen - *offset)
len = datalen - *offset;
if (copy_to_user(buf, data + *offset, len))
return -EFAULT;
*offset += len;
return len;
}
static ssize_t my_write(struct file *file, const char __user *buf,
size_t len, loff_t *offset)
{
printk(KERN_INFO "Received %zu bytes\n", len);
return len;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write,
};
static int __init my_init(void)
{
dev_t dev;
// 分配设备号
if (alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME) < 0) {
printk(KERN_ERR "Failed to allocate major number\n");
return -1;
}
major_number = MAJOR(dev);
// 初始化cdev
cdev_init(&my_cdev, &fops);
my_cdev.owner = THIS_MODULE;
if (cdev_add(&my_cdev, dev, 1) < 0) {
unregister_chrdev_region(dev, 1);
return -1;
}
// 创建设备类
my_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(my_class)) {
cdev_del(&my_cdev);
unregister_chrdev_region(dev, 1);
return PTR_ERR(my_class);
}
// 创建设备节点
my_device = device_create(my_class, NULL, dev, NULL, DEVICE_NAME);
if (IS_ERR(my_device)) {
class_destroy(my_class);
cdev_del(&my_cdev);
unregister_chrdev_region(dev, 1);
return PTR_ERR(my_device);
}
printk(KERN_INFO "Device registered with major %d\n", major_number);
return 0;
}
static void __exit my_exit(void)
{
dev_t dev = MKDEV(major_number, 0);
device_destroy(my_class, dev);
class_destroy(my_class);
cdev_del(&my_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device unregistered\n");
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");