Linux Kernel mbox_controller_register
的作用与使用示例
1. 简介
mbox_controller_register
是 Linux 内核中邮箱子系统的重要接口,用于将一个邮箱控制器注册到内核的邮箱子系统。邮箱子系统(Mailbox Subsystem)提供了硬件模块间的通信机制,支持内核态和用户态的灵活访问。
本文详细讲解 mbox_controller_register
的作用及其在 内核态模块 和 用户态程序 中的使用方法。
2. 内核态的作用与使用
2.1 邮箱子系统的作用
- 硬件抽象:通过邮箱子系统,开发者可以屏蔽底层硬件差异,实现统一的通信接口。
- 资源管理:通过
devm
机制,邮箱控制器的资源可以自动管理,避免内存泄漏。
2.2 使用步骤
(1) 注册邮箱控制器
使用 devm_mbox_controller_register
将邮箱控制器注册到子系统。
int devm_mbox_controller_register(struct device *dev, struct mbox_controller *mbox);
dev
:设备结构体指针。mbox
:邮箱控制器结构体指针。
(2) 定义邮箱控制器
struct mbox_controller
定义了邮箱控制器的属性和功能。
示例:
static struct mbox_controller my_mbox_controller = {.dev = &pdev->dev, // 指向绑定的设备.ops = &my_mbox_ops, // 操作集合.num_chans = 4, // 通道数.chans = my_mbox_chans, // 通道数组.txdone_irq = false, // 是否通过中断确认发送完成.txdone_poll = true, // 是否通过轮询确认发送完成
};
(3) 定义邮箱操作集合
操作集合定义了邮箱的具体实现逻辑,包括数据发送、启动和关闭操作。
static const struct mbox_chan_ops my_mbox_ops = {.send_data = my_mbox_send_data,.startup = my_mbox_startup,.shutdown = my_mbox_shutdown,
};
(4) 在驱动中注册
调用 devm_mbox_controller_register
完成注册:
ret = devm_mbox_controller_register(&pdev->dev, &my_mbox_controller);
if (ret) {dev_err(&pdev->dev, "Failed to register mailbox controller: %d\n", ret);return ret;
}
(5) 内核模块访问邮箱
- 请求邮箱通道:
struct mbox_chan *chan;
struct mbox_client client = {.dev = &pdev->dev,.tx_done = tx_done_callback, // 发送完成回调.rx_callback = rx_callback, // 接收消息回调.tx_block = false, // 是否阻塞发送.knows_txdone = false, // 是否需要确认发送完成
};chan = mbox_request_channel(&client, 0);
if (IS_ERR(chan)) {dev_err(&pdev->dev, "Failed to request mailbox channel\n");return PTR_ERR(chan);
}
- 发送数据:
char message[] = "Hello from kernel!";
int ret = mbox_send_message(chan, message);
if (ret < 0) {pr_err("Failed to send message: %d\n", ret);
}
- 接收数据:
static void rx_callback(struct mbox_client *client, void *data)
{pr_info("Received message: %s\n", (char *)data);
}
- 释放资源:
mbox_free_channel(chan);
3. 用户态的作用与使用
用户态程序可以通过内核驱动提供的接口与邮箱通信。常见方式包括字符设备和 ioctl
操作。
3.1 在设备树中定义邮箱
通过设备树描述邮箱节点:
mailbox0: mailbox@0 {compatible = "vendor,mailbox";reg = <0x0 0x1000>; // 假设邮箱寄存器地址范围
};
3.2 驱动中实现接口
注册字符设备
在驱动中创建字符设备,暴露给用户态:
static const struct file_operations my_mbox_fops = {.owner = THIS_MODULE,.write = my_mbox_write,
};register_chrdev(100, "my_mailbox", &my_mbox_fops);
数据写入接口
static ssize_t my_mbox_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{char message[128];if (copy_from_user(message, buf, count))return -EFAULT;mbox_send_message(chan, message);return count;
}
3.3 用户态程序访问
用户态通过字符设备发送消息:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>int main() {int fd = open("/dev/my_mailbox", O_WRONLY);if (fd < 0) {perror("Failed to open mailbox");return -1;}write(fd, "Hello mailbox!", 15);close(fd);return 0;
}
4. 示例代码
驱动代码
完整的驱动代码示例:
#include <linux/module.h>
#include <linux/mailbox_controller.h>
#include <linux/fs.h>static struct mbox_chan my_mbox_chans[2];static const struct mbox_chan_ops my_mbox_ops = {.send_data = my_send_function,.startup = my_startup_function,.shutdown = my_shutdown_function,
};static struct mbox_controller my_mbox_controller = {.ops = &my_mbox_ops,.num_chans = ARRAY_SIZE(my_mbox_chans),.chans = my_mbox_chans,
};static int my_mbox_open(struct inode *inode, struct file *file)
{return 0;
}static ssize_t my_mbox_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{char message[128];if (copy_from_user(message, buf, count))return -EFAULT;mbox_send_message(&my_mbox_chans[0], message);return count;
}static const struct file_operations my_mbox_fops = {.owner = THIS_MODULE,.open = my_mbox_open,.write = my_mbox_write,
};static int __init my_mbox_init(void)
{int ret;my_mbox_controller.dev = &pdev->dev;ret = devm_mbox_controller_register(&pdev->dev, &my_mbox_controller);if (ret)return ret;register_chrdev(100, "my_mailbox", &my_mbox_fops);return 0;
}module_init(my_mbox_init);
MODULE_LICENSE("GPL");
用户态代码
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>int main() {int fd = open("/dev/my_mailbox", O_WRONLY);if (fd < 0) {perror("Failed to open mailbox");return -1;}write(fd, "Hello mailbox!", 15);close(fd);return 0;
}
5. 总结
- 内核态通过
mbox_request_channel
获取通道,与邮箱子系统通信。 - 用户态通过驱动提供的接口(如字符设备或
ioctl
)实现与邮箱的交互。 - 邮箱机制广泛用于 SoC 间通信或硬件模块间的消息传递,是嵌入式开发中的重要组件。