文章目录
- 新增 C 文件
- 修改 Makefile 文件
- 修改 Kconfig 文件
- 模块使能
- 内核启动日志
- 参考
linux 驱动——字符设备驱动
linux 驱动——字符设备驱动(自动生成设备节点文件)
linux 驱动——将模块编译进内核
前面两节介绍的驱动都是以模块的形式,需要手动加载,本节介绍如何将模块编译进内核
新增 C 文件
#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/uaccess.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */
#define CHRDEVBASE_NUM 1 /* 设备数目 */
static char write_buf[100];
static char read_buf[100];
static char *string_test = "kernel data this tyustli test";
typedef struct {
dev_t dev_id; /* 设备号 */
struct cdev c_dev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
} new_chrdev_t;
new_chrdev_t new_chrdev;
static int chrdevbase_open(struct inode *inode, struct file *file)
{
printk("k: chrdevbase open\r\n");
return 0;
}
static ssize_t chrdevbase_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long ret = 0;
printk("k: chrdevbase read\r\n");
memcpy(read_buf, string_test, strlen(string_test));
ret = copy_to_user(buf, read_buf, count);
if (ret == 0) {
printk("k: read data success\r\n");
} else {
printk("k: read data failed ret = %ld\r\n", ret);
}
return ret;
}
static ssize_t chrdevbase_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long ret = 0;
printk("k: chrdevbase write\r\n");
ret = copy_from_user(write_buf, buf, count);
if (ret == 0) {
printk("k: write data success write data is: %s\r\n", write_buf);
} else {
printk("k: write data failed ret = %ld\r\n", ret);
}
return count;
}
static int chrdevbase_release(struct inode *inode, struct file *file)
{
printk("k: chrdevbase release\r\n");
return 0;
}
static struct file_operations chrdevbase_fops = {
.owner = THIS_MODULE,
.open = chrdevbase_open,
.read = chrdevbase_read,
.write = chrdevbase_write,
.release = chrdevbase_release,
};
static int __init chrdevbase_init(void)
{
int err = 0;
err = alloc_chrdev_region(&new_chrdev.dev_id, 0, CHRDEVBASE_NUM,
CHRDEVBASE_NAME);
if (err < 0) {
printk("k: alloc chrdev region failed err = %d\r\n", err);
return -1;
}
/* get major and minor */
new_chrdev.major = MAJOR(new_chrdev.dev_id);
new_chrdev.minor = MINOR(new_chrdev.dev_id);
printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev.major,
new_chrdev.minor);
new_chrdev.c_dev.owner = THIS_MODULE;
cdev_init(&new_chrdev.c_dev, &chrdevbase_fops);
err = cdev_add(&new_chrdev.c_dev, new_chrdev.dev_id, CHRDEVBASE_NUM);
if (err < 0) {
printk("k: cdev add failed err = %d\r\n", err);
goto out;
}
new_chrdev.class = class_create(CHRDEVBASE_NAME);
if (IS_ERR(new_chrdev.class)) {
printk("k: class create failed\r\n");
goto out_cdev;
}
new_chrdev.device = device_create(new_chrdev.class, NULL, new_chrdev.dev_id,
NULL, CHRDEVBASE_NAME);
if (IS_ERR(new_chrdev.device)) {
printk("k: device create failed\r\n");
goto out_class;
}
printk("k: base module init\r\n");
return 0;
out_class:
class_destroy(new_chrdev.class);
out_cdev:
cdev_del(&new_chrdev.c_dev);
out:
unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);
return err;
}
static void __exit chrdevbase_exit(void)
{
device_destroy(new_chrdev.class, new_chrdev.dev_id);
class_destroy(new_chrdev.class);
cdev_del(&new_chrdev.c_dev);
unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);
printk("k: base module exit!\r\n");
}
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyustli");
MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */
将上一节中的模块源码拷贝到 drivers/char
目录下
修改 Makefile 文件
CONFIG_MY_MODULE
是配置宏,如果定义了该宏,就是obj-y
+=my_module.o
my_module.o
就是自己新增 C 文件,这里写.o
即可
修改 Kconfig 文件
Makefile
文件中依赖的是CONFIG_MY_MODULE
宏,所以这里定义MY_MODULE
宏即可。
模块使能
空格即可选中
Shift + ?
可以显示帮助信息
内核启动日志
workingset: timestamp_bits=30 max_order=17 bucket_order=0
squashfs: version 4.0 (2009/01/31) Phillip Lougher
jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
9p: Installing v9fs 9p2000 file system support
io scheduler mq-deadline registered
io scheduler kyber registered
io scheduler bfq registered
k: newcheled major=250,minor=0
k: base module init
OF: graph: no port node found in /bus@40000000/motherboard-bus@40000000/iofpga@7,00000000/i2c@16000/dvi-transmitter@60
sii902x 0-0060: supply iovcc not found, using dummy regulator
sii902x 0-0060: supply cvcc12 not found, using dummy regulator
simple-pm-bus bus@40000000:motherboard-bus@40000000:iofpga@7,00000000: Failed to create device link (0x180) with dcc:tcrefclk
simple-pm-bus bus@40000000:motherboard-bus@40000000:iofpga@7,00000000: Failed to create device link (0x180) with dcc:tcrefclk
physmap-flash 40000000.flash: physmap platform flash device: [mem 0x40000000-0x43ffffff]
40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000
k: newcheled major=250,minor=0
k: base module init
自动打印出来了
参考
- https://www.rt-thread.org/document/site/#/development-tools/build-config-system/Kconfig