設(shè)備的名字和設(shè)備類
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#define DEVICE_NAME "mydevice"
#define CLASS_NAME "myclass"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple character device driver example");
static int major_number;
static struct class* myclass = NULL;
static struct device* mydevice = NULL;
static struct cdev my_cdev;
// 設(shè)備緩沖區(qū)
static char *device_buffer;
static int buffer_size = 1024;
static int buffer_offset = 0;
// 文件操作結(jié)構(gòu)體
static int mydevice_open(struct inode *inode, struct file *file);
static int mydevice_release(struct inode *inode, struct file *file);
static ssize_t mydevice_read(struct file *file, char __user *buf, size_t len, loff_t *offset);
static ssize_t mydevice_write(struct file *file, const char __user *buf, size_t len, loff_t *offset);
static struct file_operations fops = {
.open = mydevice_open,
.release = mydevice_release,
.read = mydevice_read,
.write = mydevice_write,
};
// 打開設(shè)備
static int mydevice_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "mydevice: Device opened\n");
return 0;
}
// 釋放設(shè)備
static int mydevice_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "mydevice: Device closed\n");
return 0;
}
// 讀取設(shè)備
static ssize_t mydevice_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
{
int bytes_to_read;
int bytes_read = 0;
if (*offset >= buffer_offset)
return 0;
bytes_to_read = min(len, (size_t)(buffer_offset - *offset));
if (copy_to_user(buf, device_buffer + *offset, bytes_to_read)) {
return -EFAULT;
}
*offset += bytes_to_read;
bytes_read = bytes_to_read;
printk(KERN_INFO "mydevice: Read %d bytes\n", bytes_read);
return bytes_read;
}
// 寫入設(shè)備
static ssize_t mydevice_write(struct file *file, const char __user *buf, size_t len, loff_t *offset)
{
int bytes_to_write;
int bytes_written = 0;
bytes_to_write = min(len, (size_t)(buffer_size - buffer_offset));
if (copy_from_user(device_buffer + buffer_offset, buf, bytes_to_write)) {
return -EFAULT;
}
buffer_offset += bytes_to_write;
bytes_written = bytes_to_write;
printk(KERN_INFO "mydevice: Wrote %d bytes\n", bytes_written);
return bytes_written;
}
// 模塊初始化
static int __init mydevice_init(void)
{
dev_t dev = 0; // 顯式初始化設(shè)備號(hào)變量
// 分配設(shè)備號(hào)(修復(fù)此處)
if (alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME) < 0) {
printk(KERN_ALERT "Failed to allocate device number\n");
return -1;
}
major_number = MAJOR(dev); // 提取主設(shè)備號(hào)
printk(KERN_INFO "mydevice: Registered with major number %d\n", major_number);
// 創(chuàng)建設(shè)備類
myclass = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(myclass)) {
unregister_chrdev_region(major_number, 1);
printk(KERN_ALERT "Failed to create device class\n");
return PTR_ERR(myclass);
}
// 初始化字符設(shè)備
cdev_init(&my_cdev, &fops);
my_cdev.owner = THIS_MODULE;
// 添加字符設(shè)備
if (cdev_add(&my_cdev, major_number, 1) < 0) {
class_destroy(myclass);
unregister_chrdev_region(major_number, 1);
printk(KERN_ALERT "Failed to add character device\n");
return -1;
}
// 創(chuàng)建設(shè)備節(jié)點(diǎn)
mydevice = device_create(myclass, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME);
if (IS_ERR(mydevice)) {
cdev_del(&my_cdev);
class_destroy(myclass);
unregister_chrdev_region(major_number, 1);
printk(KERN_ALERT "Failed to create device\n");
return PTR_ERR(mydevice);
}
// 分配設(shè)備緩沖區(qū)
device_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!device_buffer) {
device_destroy(myclass, MKDEV(major_number, 0));
cdev_del(&my_cdev);
class_destroy(myclass);
unregister_chrdev_region(major_number, 1);
printk(KERN_ALERT "Failed to allocate device buffer\n");
return -ENOMEM;
}
printk(KERN_INFO "mydevice: Device driver loaded successfully\n");
return 0;
}
// 模塊清理
static void __exit mydevice_exit(void)
{
// 釋放資源
device_destroy(myclass, MKDEV(major_number, 0));
cdev_del(&my_cdev);
class_destroy(myclass);
unregister_chrdev_region(major_number, 1);
kfree(device_buffer);
printk(KERN_INFO "mydevice: Device driver unloaded\n");
}
module_init(mydevice_init);
module_exit(mydevice_exit);
2. Makefile
obj-m := mydevice.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
3. 編譯和測(cè)試
編譯驅(qū)動(dòng)
make
加載驅(qū)動(dòng)
sudo insmod mydevice.ko
檢查設(shè)備文件
ls -l /dev/mydevice
你應(yīng)該會(huì)看到類似這樣的輸出:
crw------- 1 root root 245, 0 Jun 15 15:30 /dev/mydevice
查看內(nèi)核日志
dmesg | tail
測(cè)試設(shè)備
# 寫入數(shù)據(jù)
echo "Hello, Device Driver!" | sudo tee /dev/mydevice
# 讀取數(shù)據(jù)
sudo cat /dev/mydevice
卸載驅(qū)動(dòng)
sudo rmmod mydevice
4. 代碼說明
-
設(shè)備注冊(cè)流程:
-
alloc_chrdev_region()- 動(dòng)態(tài)分配設(shè)備號(hào) -
class_create()- 創(chuàng)建設(shè)備類 -
cdev_init()和cdev_add()- 初始化和添加字符設(shè)備 -
device_create()- 在/dev下創(chuàng)建設(shè)備節(jié)點(diǎn)
-
-
文件操作:
-
open- 打開設(shè)備 -
release- 關(guān)閉設(shè)備 -
read- 從設(shè)備讀取數(shù)據(jù) -
write- 向設(shè)備寫入數(shù)據(jù)
-
-
內(nèi)存管理:
-
kmalloc分配內(nèi)核內(nèi)存 -
copy_to_user和copy_from_user用于用戶空間和內(nèi)核空間的數(shù)據(jù)交換
-
-
錯(cuò)誤處理:
-
每個(gè)步驟都有適當(dāng)?shù)腻e(cuò)誤檢查和資源釋放
-
5. 擴(kuò)展功能
你可以擴(kuò)展這個(gè)驅(qū)動(dòng)來支持更多功能:
-
添加
ioctl接口實(shí)現(xiàn)設(shè)備控制 -
支持多個(gè)次設(shè)備號(hào)
-
實(shí)現(xiàn)更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)
-
添加同步機(jī)制(如互斥鎖)保護(hù)共享數(shù)據(jù)
這個(gè)示例提供了一個(gè)完整的框架,可以幫助你理解Linux字符設(shè)備驅(qū)動(dòng)的基本結(jié)構(gòu)和實(shí)現(xiàn)方法。

浙公網(wǎng)安備 33010602011771號(hào)