好吧,这对我来说真的很奇怪。我有一个模拟的 CAN 总线驱动程序,它是一个 Linux 内核模块。然后我有一个在用户空间中运行的测试应用程序,它通过打开文件描述符并发送来访问驱动程序ioctl()
消息。
现在 CAN 总线驱动程序只是我一直采用的在 x86 平台上运行的东西(它在我们的嵌入式 Coldfire 系统上运行)。在嵌入式系统上它必须使用request_mem_region()
/ioremap()
为了让内存 I/O 区域可访问,我不need这样做,但我想尽可能保持代码的通用性。
以下是一些有用的定义:
#define MCF_MBAR 0x10000000
extern unsigned int Base[];
extern unsigned int can_range[];
//This is the CAN registers on coldfire, just unused on my x86 desktop
Base[minor] = (MCF_MBAR + 0x1c0000);
can_range[minor] = 0x180;
然后在初始化期间我们这样做:
if(NULL == request_mem_region(Base[minor], can_range[minor], "CAN-IO")) {
return -EBUSY;
}
can_base[minor] = ioremap(Base[minor], can_range[minor]);
现在,如果我理解正确的话……我们在这里所做的就是请求保留一系列未分配的内存地址,如果我们成功,则使我们可以访问它们。
我通过检查当前映射的地址cat /proc/iomem
:
00000000-0000ffff : reserved
00010000-0009fbff : System RAM
0009fc00-0009ffff : reserved
000a0000-000bffff : Video RAM area
000c0000-000c8fff : Video ROM
000e2000-000e6fff : Adapter ROM
000f0000-000fffff : reserved
000f0000-000fffff : System ROM
00100000-1ffeffff : System RAM
00200000-0071038b : Kernel code
0071038c-00ad8a7f : Kernel data
00b58000-00c52fff : Kernel bss
<-- 101C0000-101C0180 : This is where I'd be mapping memory
1fff0000-1fffffff : ACPI Tables
e0000000-e0ffffff : 0000:00:02.0
e0000000-e0bfffff : vesafb
f0000000-f001ffff : 0000:00:03.0
f0000000-f001ffff : e1000
f0400000-f07fffff : 0000:00:04.0
f0400000-f07fffff : vboxguest
f0800000-f0803fff : 0000:00:04.0
f0804000-f0804fff : 0000:00:06.0
f0804000-f0804fff : ohci_hcd
f0806000-f0807fff : 0000:00:0d.0
f0806000-f0807fff : ahci
fee00000-fee00fff : Local APIC
fffc0000-ffffffff : reserved
看起来没有任何东西使用该内存,所以我想我在这里没问题。因此,我成功加载了内核模块,然后去运行我的测试程序,但失败了,再次运行它,它就可以工作了。
每次你在新加载后第一次运行它,它都会失败......第二次,第三次,第n次,它会工作:
mike@linux-4puc:~> ./a.out
Starting driver test
Error 'Device or resource busy' opening CAN device
mike@linux-4puc:~> ./a.out
Starting driver test
We opened successfully
这是我非常简单的用户空间程序的一部分:
int fd;
char* dev = "/dev/can0";
printf("Starting driver test\n");
if ((fd = open(dev, O_RDWR)) < 0) {
printf("Error '%s' opening CAN device", strerror(errno));
close(fd);
return -1;
}
关于为什么会发生这种情况有什么想法吗?如果我删除request_mem_region()
我的驱动程序中的代码一切正常,所以我认为我只是做了一些愚蠢的事情......但为什么它会以这种方式失败?