2

我是内核编程的新手,现在尝试将一些值写入设备驱动程序中的 32 位 GPIO 寄存器。I/O 被ioremap()编辑到一个内存地址。问题是,我不知道writel()//如何将writeb()writew()写入地址。

供应商文件说登记在上0xE5200000。我必须写入的位是[0:3]位,并将剩余的 28 位([4:31]位)保留为零。

这是迄今为止我编写的设备驱动程序代码的一部分:

#define TCON_ADDR 0xE250000 // The address as provided by the vendor
static void *TIMER_CON_ADDR;
// I have to map and write to the address when the device is opened
static int on_dev_open(struct inode *inode, struct file *file) {
    unsigned int data;
    TIMER_CON_ADDR = ioremap(TCON_ADDR, 4); // Map the [0:4] bits to TIMER_CON_ADDR
    data = 4; // 0100 in binary
    writel(data, TIMER_CON_ADDR); // Write 0100 to TIMER_CON_ADDR
    return 0;
}

上面的代码对你们来说可能是彻头彻尾的胡言乱语,但我不熟悉write(l|w|b)and ioremap()

所以我的问题是:

  1. 我是否正确地将这些[0:4]位映射到 TIMER_CON_ADDR?
  2. 如果没有,我该如何正确映射它们?
  3. 正确映射 4 位后,如何使用任何write(1|w|b)函数以正确的顺序将位 ( 0100) 写入 TIMER_CON_ADDR?
  4. 在引擎盖下做什么write(l|w|b)来写入位?
  5. 有没有我错过/弄错的信息?

感谢您提前提供的所有帮助。

4

1 回答 1

5
  1. 我是否正确地将这些[0:4]位映射到 TIMER_CON_ADDR?

不,你写 32 位,writel 写 4 个字节,4 * 8 = 32 位

  1. 如果没有,我该如何正确映射它们?

无法映射 4 位,最少 8 位 = 1 字节,但如果使用 32 位寄存器,则需要映射 32 位 = 4 字节。也不要忘记检查和处理错误。

  1. 正确映射 4 位后,如何使用任何write(1|w|b)函数以正确的顺序将位 ( 0100) 写入 TIMER_CON_ADDR?

您需要使用 readl,内核充满示例,只需grepdriverslinux 内核源代码树的子目录中运行。总体思路读/写:

u32 reg = readl(TIMER_CON_ADDR);
reg &= ~0xfu;
reg |= 4;
writel(reg, TIMER_CON_ADDR);
  1. 在引擎盖下做什么write(l|w|b)来写入位?

查看源代码,它只是简单的 C 函数,例如:

static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
    *(volatile u32 __force *)addr = value;
}

主要思想是告诉编译器它不应该删除你的内存读/写

  1. 有没有我错过/弄错的信息?

阅读类似驱动程序的源代码,它已经包含了此类简单驱动程序的几乎所有解决方案。

于 2017-04-02T08:22:32.890 回答