創(chuàng)建自定義的IOCTL(輸入/輸出控制)或Netlink命令以便用戶空間程序與內(nèi)核模塊交互涉及幾個(gè)步驟。這里將分別介紹這兩種方法。
一、IOCTL 方法
1. 定義IOCTL命令
在內(nèi)核模塊中,需要使用宏定義你的IOCTL命令。通常情況下,IOCTL命令包括了一個(gè)命令編號(hào)、請(qǐng)求類(lèi)型的方向(讀/寫(xiě)/兩者)以及數(shù)據(jù)大小:
#include <linux/ioctl.h>
#define MY_IOCTL_TYPE 'x' // 通常是一個(gè)字符
#define MY_IOCTL_CMD1 _IOR(MY_IOCTL_TYPE, 1, my_data_struct)
#define MY_IOCTL_CMD2 _IOW(MY_IOCTL_TYPE, 2, my_data_struct)
// ...
2. 實(shí)現(xiàn)ioctl函數(shù)
在你的內(nèi)核模塊中,實(shí)現(xiàn)ioctl系統(tǒng)調(diào)用的函數(shù)處理:
static long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
my_data_struct data;
switch (cmd) {
case MY_IOCTL_CMD1:
if (copy_from_user(&data, (my_data_struct __user *)arg, sizeof(data)))
return -EFAULT;
// 處理MY_IOCTL_CMD1
break;
case MY_IOCTL_CMD2:
// 處理MY_IOCTL_CMD2
if (copy_to_user((my_data_struct __user *)arg, &data, sizeof(data)))
return -EFAULT;
break;
default:
return -ENOTTY; // 未知的命令
}
return 0; // 成功
}
const struct file_operations fops = {
.unlocked_ioctl = my_ioctl,
// 其他的file_operations成員
};
3. 在用戶空間調(diào)用IOCTL
應(yīng)用程序使用`ioctl`系統(tǒng)調(diào)用與內(nèi)核模塊交流:
#include <sys/ioctl.h>
#include <fcntl.h>
int fd = open("/dev/mydevice", O_RDWR);
my_data_struct data;
// 設(shè)置 data
ioctl(fd, MY_IOCTL_CMD2, &data);
// 讀取 data
ioctl(fd, MY_IOCTL_CMD1, &data);
close(fd);
二、Netlink 方法
1. 初始化Netlink Socket
在內(nèi)核模塊中,創(chuàng)建并初始化Netlink Socket:
#include <net/sock.h>
struct sock *nl_sk = NULL;
static void nl_recv_msg(struct sk_buff *skb) {
// 從skb中解析出消息并處理
}
static int __init my_module_init(void) {
struct netlink_kernel_cfg cfg = {
.input = nl_recv_msg,
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
return 0;
}
2. 實(shí)現(xiàn)Netlink消息處理函數(shù)
如上所示,`nl_recv_msg`是在用戶空間發(fā)送消息到內(nèi)核時(shí)調(diào)用的接收消息處理函數(shù)。處理邏輯根據(jù)具體需求實(shí)現(xiàn)。
3. 用戶空間程序
在用戶空間程序中,使用Netlink進(jìn)行通訊:
#include <sys/socket.h>
#include <linux/netlink.h>
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
int nl_sock;
// 創(chuàng)建Netlink Socket
nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
// 初始化地址結(jié)構(gòu)
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); // 自進(jìn)程ID
bind(nl_sock, (struct sockaddr*)&src_addr, sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; // 對(duì)端的ID,0表示內(nèi)核
dest_addr.nl_groups = 0; // 無(wú)組播
// 發(fā)送消息到內(nèi)核
記得在模塊中注冊(cè)Netlink操作,并且在模塊退出時(shí)釋放Netlink Socket,用戶空間程序需要負(fù)責(zé)構(gòu)造和解碼Netlink消息。以上只是一個(gè)概述,實(shí)現(xiàn)時(shí)往往需要處理更多的細(xì)節(jié)和錯(cuò)誤情況。
三、創(chuàng)建一個(gè)字符設(shè)備讓用戶空間程序進(jìn)行讀寫(xiě)操作,內(nèi)核模塊可以對(duì)這些操作進(jìn)行響應(yīng)
在Linux中,字符設(shè)備是可以進(jìn)行按字節(jié)流讀寫(xiě)操作的設(shè)備。創(chuàng)建一個(gè)字符設(shè)備使得用戶空間的程序可以打開(kāi)、讀寫(xiě)、關(guān)閉等操作,并使得內(nèi)核模塊能夠?qū)@些操作進(jìn)行響應(yīng),通常是通過(guò)實(shí)現(xiàn)一個(gè)設(shè)備驅(qū)動(dòng)來(lái)完成的。`ioctl`是一個(gè)系統(tǒng)調(diào)用,用于設(shè)備特定的操作,如配置或獲取設(shè)備信息。在字符設(shè)備驅(qū)動(dòng)中實(shí)現(xiàn)`ioctl`是可選的,取決于設(shè)備是否需要提供額外的設(shè)備控制功能。
以下是創(chuàng)建和注冊(cè)字符設(shè)備的基本步驟:
1. 分配設(shè)備號(hào):
使用`alloc_chrdev_region`來(lái)動(dòng)態(tài)申請(qǐng)主設(shè)備號(hào)和從設(shè)備號(hào),或者使用`register_chrdev_region`如果你希望靜態(tài)指定設(shè)備號(hào)。
2. 創(chuàng)建設(shè)備類(lèi)和設(shè)備節(jié)點(diǎn):
通常采用`class_create`創(chuàng)建一個(gè)設(shè)備類(lèi),并使用`device_create`創(chuàng)建設(shè)備節(jié)點(diǎn)。設(shè)備節(jié)點(diǎn)是用戶空間與設(shè)備交云的接口,在`/dev/`目錄下創(chuàng)建。
3. 初始化`cdev`結(jié)構(gòu):
`cdev`結(jié)構(gòu)代表字符設(shè)備的內(nèi)核結(jié)構(gòu)。使用`cdev_init`來(lái)初始化`cdev`結(jié)構(gòu),并關(guān)聯(lián)該結(jié)構(gòu)與之前定義的文件操作函數(shù)集合。
4. 添加?cdev?到內(nèi)核中:
使用`cdev_add`將`cdev`結(jié)構(gòu)添加到內(nèi)核中,設(shè)備就會(huì)變?yōu)榛钴S狀態(tài),用戶空間就可以訪問(wèn)它了。
5. 實(shí)現(xiàn)文件操作函數(shù):
定義一個(gè)包含`open`、`release`、`read`、`write`等操作的`file_operations`結(jié)構(gòu),這樣用戶空間應(yīng)用就可以通過(guò)系統(tǒng)調(diào)用來(lái)操作驅(qū)動(dòng)。
例如,以下代碼段演示了以上步驟的基本框架:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-808636.html
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
static int major;
static struct class *my_class;
static struct cdev my_cdev;
static int my_open(struct inode *inode, struct file *file)
{
// 打開(kāi)設(shè)備的代碼
return 0;
}
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
{
// 讀取設(shè)備的代碼
return 0; // 返回讀取的字節(jié)數(shù)
}
static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
// 寫(xiě)入設(shè)備的代碼
return count; // 返回寫(xiě)入的字節(jié)數(shù)
}
static int my_release(struct inode *inode, struct file *file)
{
// 關(guān)閉設(shè)備的代碼
return 0;
}
static const struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = my_open,
.read = my_read,
.write = my_write,
.release = my_release,
// 如果你需要使用ioctl,則在這里添加.unlocked_ioctl = my_ioctl,
};
static int __init my_init(void)
{
dev_t dev_id;
// 1. 分配設(shè)備號(hào)
if (alloc_chrdev_region(&dev_id, 0, 1, "my_device") < 0) {
return -1;
}
major = MAJOR(dev_id);
// 2. 創(chuàng)建設(shè)備類(lèi)和設(shè)備節(jié)點(diǎn)
my_class = class_create(THIS_MODULE, "my_device_class");
device_create(my_class, NULL, dev_id, NULL, "mydevice");
// 3. 初始化cdev結(jié)構(gòu)
cdev_init(&my_cdev, &my_fops);
// 4. 添加cdev到內(nèi)核中
if (cdev_add(&my_cdev, dev_id, 1) < 0) {
unregister_chrdev_region(dev_id, 1);
return -1;
}
return 0;
}
static void __exit my_exit(void)
{
dev_t dev_id = MKDEV(major, 0);
// 5. 從系統(tǒng)中刪除cdev
cdev_del(&my_cdev);
// 銷(xiāo)毀設(shè)備節(jié)點(diǎn)和設(shè)備類(lèi)
device_destroy(my_class, dev_id);
class_destroy(my_class);
// 釋放設(shè)備號(hào)
unregister_chrdev_region(dev_id, 1);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
在`my_fops`中,你可以實(shí)現(xiàn)`.unlocked_ioctl`(或`.ioctl`,取決于內(nèi)核版本)來(lái)響應(yīng)`ioctl`調(diào)用。請(qǐng)注意,這只是一個(gè)簡(jiǎn)單的框架。在實(shí)際的驅(qū)動(dòng)實(shí)現(xiàn)中,你將需要填充這些函數(shù),處理錯(cuò)誤情況,并且可能需要處理并發(fā)控制和同步問(wèn)題。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-808636.html
到了這里,關(guān)于【linux驅(qū)動(dòng)】用戶空間程序與內(nèi)核模塊交互-- IOCTL和Netlink的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!