【发布时间】:2013-04-17 18:54:46
【问题描述】:
我正在编写一个简单的 Linux 字符设备驱动程序,以通过 I/O 端口将数据输出到硬件。我有一个函数可以执行浮点运算来计算硬件的正确输出;不幸的是,这意味着我需要将此函数保留在用户空间中,因为 Linux 内核不能很好地处理浮点运算。
这是设置的伪表示(请注意,此代码没有做任何具体的事情,它只是显示我的代码的相对布局):
用户空间功能:
char calculate_output(char x){
double y = 2.5*x;
double z = sqrt(y);
char output = 0xA3;
if(z > 35.67){
output = 0xC0;
}
return output;
}
内核空间代码:
unsigned i;
for(i = 0; i < 300; i++){
if(inb(INPUT_PORT) & NEED_DATA){
char seed = inb(SEED_PORT);
char output = calculate_output(seed);
outb(output, OUTPUT_PORT);
}
/* do some random stuff here */
}
我考虑过使用ioctl 从用户空间函数传递数据,但我不确定如何处理函数调用处于循环中并且在下一次调用@987654324 之前执行更多代码的事实@ 出现。
我设想的工作方式是:
- 主用户空间程序将启动内核空间代码(可能通过
ioctl) - 用户空间程序阻塞并等待内核空间代码
- 内核空间程序询问用户空间程序输出数据,并阻塞等待
- 用户空间程序解除阻塞,计算并发送数据 (
ioctl?),然后再次阻塞 - 内核空间程序解除阻塞并继续
- 内核空间程序完成并通知用户空间
- 用户空间解除阻塞并继续下一个任务
那么我如何在内核空间和用户空间之间进行通信,并且还有阻塞,这样我就不会让用户空间不断轮询设备文件以查看它是否需要发送数据?
警告:虽然在我的示例代码中定点运算可以很好地工作,但在实际代码中它不是一个选项;我需要浮点提供的大范围,而且——即使没有——我担心重写代码以使用定点算术会混淆未来维护者的算法。
【问题讨论】:
-
您是否有机会拥有用户空间中的几乎所有东西,并且只在内核中提供一个瘦接口启用程序?
-
@ChrisStratton 这就是我想要实现的目标。在 for 循环中发生的东西是更多杂项硬件输出(简单的 outb 调用,仅此而已)。
-
@ChrisStratton 哦等等,你的意思是把
for循环移到内核之外吗? -
可以发送信号和执行用户空间应用程序,但它不是一个通用的接口。您是否计划让内核线程执行需要用户空间数据的操作?在这种情况下,您可以通过 write/ioctl 从用户空间写入 kfifo,然后从内核线程中读取此数据。不需要阻止。
-
IMO 的偏好应该始终是尽可能多地放在用户空间中。 Userland 代码往往更易于移植。考虑原始硬件平台停产的场景(我在几年前就看到过这种情况)。替代硬件平台更快、更便宜且架构不同——意味着新内核。因此,您在内核中放入的非硬件特定的定制越少越好。
标签: c linux linux-kernel driver linux-device-driver