添加 request_mem_region 后,我的驱动程序每次第一次访问都会失败,并显示“忙”消息

2024-03-30

好吧,这对我来说真的很奇怪。我有一个模拟的 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()我的驱动程序中的代码一切正常,所以我认为我只是做了一些愚蠢的事情......但为什么它会以这种方式失败?


我有点惊讶这对你有用。这request_mem_region()传递的值为0x101C0000它在系统RAM的物理地址范围内,0x00100000:0x1ffeffff。我猜想(初始)错误返回表明内核已经将此物理内存区域安装到其内存池中。当驱动程序错误退出时(或模块卸载时),它是否尝试进行适当的清理并调用release_mem_region(),这可能会成功request_mem_region()下一次复飞?

通常你会提供request_mem_region()地址范围是not正在使用中(即当前unknown到内核​​),因为驱动程序正在使该物理地址范围“可用”(即声明用于映射到虚拟地址空间的物理地址范围)。

如果你使用类似的东西会发生什么

#define MCF_MBAR    0x90000000

假设该物理地址空间确实未使用?

顺便说一句,如果您的司机打电话来release_mem_region()第一次使用后,驱动程序出现错误。驱动程序应该只释放它实际获取的资源。如果request_mem_region()返回错误,则永远不会获取内存资源。因此没有理由打电话release_mem_region()(并且驱动程序总是会在_init())。如果您检查一些正常运行的 Linux 设备驱动程序,您可能会发现精心设计的错误退出方案(使用goto语句)来展开分配的资源_init()释放前的例行检查和有效性检查_exit() code.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

添加 request_mem_region 后,我的驱动程序每次第一次访问都会失败,并显示“忙”消息 的相关文章

  • 如何将 protobuf-net 与不可变值类型一起使用?

    假设我有一个像这样的不可变值类型 Serializable DataContract public struct MyValueType ISerializable private readonly int x private readon
  • 在 DataView 的 RowFilter 中选择 DISTINCT

    我试图根据与另一个表的关系缩小 DataView 中的行范围 我使用的 RowFilter 如下 dv new DataView myDS myTable id IN SELECT DISTINCT parentID FROM myOthe
  • MVC 在布局代码之前执行视图代码并破坏我的脚本顺序

    我正在尝试将所有 javascript 包含内容移至页面底部 我正在将 MVC 与 Razor 一起使用 我编写了一个辅助方法来注册脚本 它按注册顺序保留脚本 并排除重复的内容 Html RegisterScript scripts som
  • 为什么极端下派生类(多重虚拟继承)的大小包括超类成员大小的两倍?

    include
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 如何区分用户点击链接和页面自动重定向?

    拥有 C WebBrowser control http msdn microsoft com en us library system windows forms webbrowser aspx在我的 WinForms 应用程序中 并意识
  • 回发后刷新时提示确认表单重新提交。我做错了什么?

    我有一个以空白 默认状态启动的仪表板 我让用户能够将保存的状态加载到仪表板中 当他们单击 应用 按钮时 我运行以下代码 function CloseAndSave var radUpload find radUpload1ID var in
  • 如何使用 LINQ2SQL 连接两个不同上下文的表?

    我的应用程序中有 2 个数据上下文 不同的数据库 并且需要能够通过上下文 B 中的表的右连接来查询上下文 A 中的表 我该如何在 LINQ2SQL 中执行此操作 Why 我们正在使用 SaaS 产品来跟踪我们的时间 项目等 并希望向该产品发
  • 我可以使用 moq Mock 来模拟类而不是接口吗?

    正在经历https github com Moq moq4 wiki Quickstart https github com Moq moq4 wiki Quickstart 我看到它 Mock 一个接口 我的遗留代码中有一个没有接口的类
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • 如何在 32 位或 64 位配置中以编程方式运行任何 CPU .NET 可执行文件?

    我有一个可在 32 位和 64 位处理器上运行的 C 应用程序 我试图枚举给定系统上所有进程的模块 当尝试从 64 位应用程序枚举 32 位进程模块时 这会出现问题 Windows 或 NET 禁止它 我认为如果我可以从应用程序内部重新启动
  • 如何禁用 fread() 中的缓冲?

    我正在使用 fread 和 fwrite 读取和写入套接字 我相信这些函数用于缓冲输入和输出 有什么方法可以在仍然使用这些功能的同时禁用缓冲吗 Edit 我正在构建一个远程桌面应用程序 远程客户端似乎 落后于服务器 我不知道可能是什么原因
  • C# 中的合并运算符?

    我想我记得看到过类似的东西 三元运算符 http msdn microsoft com en us library ty67wk28 28VS 80 29 aspx在 C 中 它只有两部分 如果变量值不为空 则返回变量值 如果为空 则返回默
  • “接口”类似于 boost::bind 的语义

    我希望能够将 Java 的接口语义与 C 结合起来 起初 我用过boost signal为给定事件回调显式注册的成员函数 这非常有效 但后来我发现一些函数回调池是相关的 因此将它们抽象出来并立即注册所有实例的相关回调是有意义的 但我了解到的
  • 如何设置 log4net 每天将我的文件记录到不同的文件夹中?

    我想将每天的所有日志保存在名为 YYYYMMdd 的文件夹中 log4net 应该根据系统日期时间处理创建新文件夹 我如何设置它 我想将一天中的所有日志保存到 n 个 1MB 的文件中 我不想重写旧文件 但想真正拥有一天中的所有日志 我该如
  • 按 Esc 按键关闭 Ajax Modal 弹出窗口

    我已经使用 Ajax 显示了一个面板弹出窗口 我要做的是当用户按 Esc 键时关闭该窗口 这可能吗 如果有人知道这一点或以前做过这一点 请帮助我 Thanks 通过以下链接 您可以通过按退出按钮轻松关闭窗口 http www codepro
  • 不同类型指针之间的减法[重复]

    这个问题在这里已经有答案了 我试图找到两个变量之间的内存距离 具体来说 我需要找到 char 数组和 int 之间的距离 char data 5 int a 0 printf p n p n data 5 a long int distan
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类
  • C++ 条件编译

    我有以下代码片段 ifdef DO LOG define log p record p else define log p endif void record char data 现在如果我打电话log hello world 在我的代码中
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看

随机推荐