使用 writel 将 4 位写入 ioremap-ed 内存地址
Using writel to write 4 bit to ioremap-ed memory address
我是内核编程的新手,现在正尝试将一些值写入设备驱动程序中的 32 位 GPIO 寄存器。 I/O 被 ioremap()
-ed 到内存地址。问题是,我不知道 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)
和 ioremap()
.
并不熟悉
所以我的问题是:
- 我是否将
[0:4]
位正确映射到 TIMER_CON_ADDR?
- 如果没有,我该如何正确映射它们?
- 在正确映射 4 位后,如何使用任何
write(1|w|b)
函数以正确的顺序将位 (0100
) 写入 TIMER_CON_ADDR?
write(l|w|b)
写入位的幕后操作是什么?
- 有没有我遗漏/弄错的信息?
提前感谢您的帮助。
- Did I map the
[0:4]
bits to TIMER_CON_ADDR correctly?
不,你写32bits,writel
写4字节,4*8=32bits
- If not, how do I map them correctly?
无法映射 4 位,最少 8 位 = 1 字节,但如果您使用 32 位
注册你需要映射 32 位 = 4 字节。也不要忘记检查和处理
错误。
- After I have correctly mapped the 4 bits, how do I use any of the
write(1|w|b)
functions to write bits (0100
) to TIMER_CON_ADDR in the correct order?
你需要使用 readl,内核充满示例,只需 运行 grep
在 linux 内核源代码树的 drivers
子目录中。
总体思路read/write:
u32 reg = readl(TIMER_CON_ADDR);
reg &= ~0xfu;
reg |= 4;
writel(reg, TIMER_CON_ADDR);
- What does
write(l|w|b)
do under the hood to write bits?
查看源代码,它只是简单的 C 函数,例如:
static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
*(volatile u32 __force *)addr = value;
}
主要思想是告诉编译器它不应该删除
你的记忆reading/writing
- Is there any information I've missed / got wrong?
阅读类似驱动的源码,已经包含了差不多
此类简单驱动程序的所有解决方案。
我是内核编程的新手,现在正尝试将一些值写入设备驱动程序中的 32 位 GPIO 寄存器。 I/O 被 ioremap()
-ed 到内存地址。问题是,我不知道 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)
和 ioremap()
.
所以我的问题是:
- 我是否将
[0:4]
位正确映射到 TIMER_CON_ADDR? - 如果没有,我该如何正确映射它们?
- 在正确映射 4 位后,如何使用任何
write(1|w|b)
函数以正确的顺序将位 (0100
) 写入 TIMER_CON_ADDR? write(l|w|b)
写入位的幕后操作是什么?- 有没有我遗漏/弄错的信息?
提前感谢您的帮助。
- Did I map the
[0:4]
bits to TIMER_CON_ADDR correctly?
不,你写32bits,writel
写4字节,4*8=32bits
- If not, how do I map them correctly?
无法映射 4 位,最少 8 位 = 1 字节,但如果您使用 32 位 注册你需要映射 32 位 = 4 字节。也不要忘记检查和处理 错误。
- After I have correctly mapped the 4 bits, how do I use any of the
write(1|w|b)
functions to write bits (0100
) to TIMER_CON_ADDR in the correct order?
你需要使用 readl,内核充满示例,只需 运行 grep
在 linux 内核源代码树的 drivers
子目录中。
总体思路read/write:
u32 reg = readl(TIMER_CON_ADDR);
reg &= ~0xfu;
reg |= 4;
writel(reg, TIMER_CON_ADDR);
- What does
write(l|w|b)
do under the hood to write bits?
查看源代码,它只是简单的 C 函数,例如:
static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
*(volatile u32 __force *)addr = value;
}
主要思想是告诉编译器它不应该删除 你的记忆reading/writing
- Is there any information I've missed / got wrong?
阅读类似驱动的源码,已经包含了差不多 此类简单驱动程序的所有解决方案。