Hello驱动

Catalogue
  1. 1. Hello驱动
    1. 1.1. 现象
    2. 1.2. 驱动代码
    3. 1.3. 相应的Makefile
    4. 1.4. 编译
    5. 1.5. 安装
    6. 1.6. 卸载
  2. 2. 参考代码
  3. 3. 参考资料

Hello驱动

为本机编译一个简单的Hello驱动程序,并安装到本机

现象

安装驱动 —- sudo insmod hello.ko

1
[1729410.050971] Hello, driver loaded!

卸载驱动 —- sudo rmmod hello

1
[1729449.769785] Goodbye, driver unloaded!

查看内核日志

1
sudo dmesg | tail

驱动代码

1
2
# 引用的库在:
/lib/modules/6.8.0-101-generic/build/include/linux
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <linux/init.h>
#include <linux/module.h>

static int __init hello_init(void)
{
printk(KERN_INFO "Hello, driver loaded!\n");
return 0;
}

static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye, driver unloaded!\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World driver");

相应的Makefile

1
2
3
4
5
6
7
obj-m += hello.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

编译

1
make

安装

1
sudo insmod hello.ko

卸载

1
sudo rmmod hello

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

#define LED_GPIO 20 // 假设LED连接到GPIO20
#define DEVICE_NAME "rk3588_led"
#define DEVICE_CLASS "led_class"

static int led_gpio = -1;
static int major_number;
static struct class *led_class = NULL;
static struct device *led_device = NULL;

// 文件操作函数声明
static int led_open(struct inode *, struct file *);
static int led_release(struct inode *, struct file *);
static ssize_t led_write(struct file *, const char __user *, size_t, loff_t *);

// 文件操作结构体
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.write = led_write,
};

// 打开设备
static int led_open(struct inode *inodep, struct file *filep)
{
printk(KERN_INFO "LED device opened\n");
return 0;
}

// 关闭设备
static int led_release(struct inode *inodep, struct file *filep)
{
printk(KERN_INFO "LED device closed\n");
return 0;
}

// 写入设备 - 控制LED开关
static ssize_t led_write(struct file *filep, const char __user *buf, size_t len, loff_t *off)
{
char kbuf[2];

// 从用户空间复制数据
if (copy_from_user(kbuf, buf, len > 1 ? 1 : len) != 0) {
printk(KERN_ERR "Failed to copy data from user\n");
return -EFAULT;
}

// 根据用户输入控制LED
if (kbuf[0] == '1') {
gpio_set_value(led_gpio, 1);
printk(KERN_INFO "LED turned ON\n");
} else if (kbuf[0] == '0') {
gpio_set_value(led_gpio, 0);
printk(KERN_INFO "LED turned OFF\n");
} else {
printk(KERN_WARNING "Invalid input. Use '1' to turn ON, '0' to turn OFF\n");
return -EINVAL;
}

return len;
}

static int __init led_init(void)
{
int ret;

// 请求GPIO
ret = gpio_request(LED_GPIO, "led_gpio");
if (ret < 0) {
printk(KERN_ERR "Failed to request GPIO %d\n", LED_GPIO);
return ret;
}

// 设置GPIO方向为输出
ret = gpio_direction_output(LED_GPIO, 0);
if (ret < 0) {
printk(KERN_ERR "Failed to set GPIO direction\n");
gpio_free(LED_GPIO);
return ret;
}

led_gpio = LED_GPIO;

// 注册字符设备
major_number = register_chrdev(0, DEVICE_NAME, &fops);
if (major_number < 0) {
printk(KERN_ERR "Failed to register character device\n");
gpio_free(led_gpio);
return major_number;
}

// 创建设备类
led_class = class_create(DEVICE_CLASS);
if (IS_ERR(led_class)) {
printk(KERN_ERR "Failed to create device class\n");
unregister_chrdev(major_number, DEVICE_NAME);
gpio_free(led_gpio);
return PTR_ERR(led_class);
}

// 创建设备文件
led_device = device_create(led_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME);
if (IS_ERR(led_device)) {
printk(KERN_ERR "Failed to create device\n");
class_destroy(led_class);
unregister_chrdev(major_number, DEVICE_NAME);
gpio_free(led_gpio);
return PTR_ERR(led_device);
}

printk(KERN_INFO "LED driver initialized\n");
printk(KERN_INFO "Device created at /dev/%s\n", DEVICE_NAME);

return 0;
}

static void __exit led_exit(void)
{
if (led_gpio >= 0) {
// 关闭LED
gpio_set_value(led_gpio, 0);
// 释放GPIO
gpio_free(led_gpio);
}

// 销毁设备
device_destroy(led_class, MKDEV(major_number, 0));
// 销毁设备类
class_destroy(led_class);
// 注销字符设备
unregister_chrdev(major_number, DEVICE_NAME);

printk(KERN_INFO "LED driver unloaded\n");
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("RK3588 LED driver with character device interface");

控制LED:

1
2
3
4
5
// 点亮LED
echo "1" | sudo tee /dev/rk3588_led

// 熄灭LED
echo "0" | sudo tee /dev/rk3588_led

参考资料