驱动源码
在驱动中直接创建字符设备节点/dev/mychardev
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#define DEVICE_NAME "mychardev"
#define CLASS_NAME "mychardev_class"
#define BUF_SIZE 1024
static char device_buf[BUF_SIZE];
static int device_open = 0;
static dev_t dev_num;
static struct class *chardev_class;
static struct device *chardev_device;
static struct cdev chardev_cdev;
static int mychardev_open(struct inode *inode, struct file *file)
{
if (device_open)
return -EBUSY;
device_open++;
return 0;
}
static int mychardev_release(struct inode *inode, struct file *file)
{
device_open--;
return 0;
}
static ssize_t mychardev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
if (copy_to_user(buf, device_buf, count) != 0)
return -EFAULT;
return count;
}
static ssize_t mychardev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
if (copy_from_user(device_buf, buf, count) != 0)
return -EFAULT;
return count;
}
static struct file_operations mychardev_fops = {
.owner = THIS_MODULE,
.open = mychardev_open,
.release = mychardev_release,
.read = mychardev_read,
.write = mychardev_write,
};
static int __init mychardev_init(void)
{
//动态申请字符设备号,参数为:返回的设备号,次设备号从几开始,个数,设备名称
if (alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME) < 0) {
printk(KERN_ERR "Failed to allocate device number\n");
return -1;
}
//初始化字符设备,主要就是关联fops和cdev结构体
cdev_init(&chardev_cdev, &mychardev_fops);
//向系统添加字符设备,参数:要添加的字符设备对象的指针,设备号,个数
if (cdev_add(&chardev_cdev, dev_num, 1) < 0) {
printk(KERN_ERR "Failed to add char device\n");
unregister_chrdev_region(dev_num, 1);
return -1;
}
//创建设备类,参数为指定拥有该设备类的内核模块,通常使用THIS_MODULE;设备类的名称
chardev_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(chardev_class)) {
printk(KERN_ERR "Failed to create device class\n");
cdev_del(&chardev_cdev);
unregister_chrdev_region(dev_num, 1);
return PTR_ERR(chardev_class);
}
//创建设备节点,参数为:设备所属的设备类;指定父设备的指针,通常为NUL;指定设备的设备号;指定与设备相关的驱动数据,通常为NULL;设备名称
chardev_device = device_create(chardev_class, NULL, dev_num, NULL, DEVICE_NAME);
if (IS_ERR(chardev_device)) {
printk(KERN_ERR "Failed to create device\n");
class_destroy(chardev_class);
cdev_del(&chardev_cdev);
unregister_chrdev_region(dev_num, 1);
return PTR_ERR(chardev_device);
}
printk(KERN_INFO "mychardev module loaded\n");
return 0;
}
static void __exit mychardev_exit(void)
{
//销毁设备
device_destroy(chardev_class, dev_num);
//注销类
class_unregister(chardev_class);
//销毁类
class_destroy(chardev_class);
//删除设备
cdev_del(&chardev_cdev);
//注销设备号
unregister_chrdev_region(dev_num, 1);
printk(KERN_INFO "mychardev module unloaded\n");
}
module_init(mychardev_init);
module_exit(mychardev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple character device driver example");
Makefile文件:
obj-m += chardev.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define DEVICE_PATH "/dev/mychardev"
#define BUF_LEN 1024
int main() {
int fd;
char read_buf[BUF_LEN];
char write_buf[BUF_LEN] = "Hello from user space!\n";
// Open device file
fd = open(DEVICE_PATH, O_RDWR);
if (fd < 0) {
perror("Failed to open the device");
return -1;
}
// Write to device
printf("Writing to device: %s\n", write_buf);
write(fd, write_buf, strlen(write_buf));
// Read from device
printf("Reading from device...\n");
read(fd, read_buf, BUF_LEN);
printf("Data read from device: %s\n", read_buf);
// Close device file
close(fd);
return 0;
}