Использование writel для записи 4-битного адреса памяти в ioremap
Я новичок в программировании ядра, и теперь пытаюсь записать некоторые значения в 32-битный регистр GPIO в драйвере устройства. Ввод / вывод 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)
а также ioremap()
,
Итак, мои вопросы:
- Я карту
[0:4]
биты в TIMER_CON_ADDR правильно? - Если нет, то как мне правильно их сопоставить?
- После того, как я правильно сопоставил 4 бита, как я могу использовать любой из
write(1|w|b)
функции для записи битов (0100
) в TIMER_CON_ADDR в правильном порядке? - Что значит
write(l|w|b)
делать под капотом писать биты? - Есть ли какая-либо информация, которую я пропустил / ошибся?
Спасибо за вашу помощь заранее.
1 ответ
- Я карту
[0:4]
биты в TIMER_CON_ADDR правильно?
нет, ты пишешь 32 бита, writel
запись 4 байта, 4 * 8 = 32 бита
- Если нет, то как мне правильно их сопоставить?
Нет способа отобразить 4 бита, минимум 8 бит = 1 байт, но если вы работаете с 32-битным регистром, вам нужно отобразить 32 бита = 4 байта. Также не забывайте проверять и обрабатывать ошибки.
- После того, как я правильно сопоставил 4 бита, как я могу использовать любой из
write(1|w|b)
функции для записи битов (0100
) в TIMER_CON_ADDR в правильном порядке?
вам нужно использовать readl, ядро полно примеров, просто запустите grep
внутри drivers
подкаталог дерева исходных текстов ядра Linux. Общая идея чтения / записи:
u32 reg = readl(TIMER_CON_ADDR);
reg &= ~0xfu;
reg |= 4;
writel(reg, TIMER_CON_ADDR);
- Что значит
write(l|w|b)
делать под капотом писать биты?
посмотрите на исходный код, это просто простые функции C, например:
static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
*(volatile u32 __force *)addr = value;
}
основная идея - сказать компилятору, что он не должен удалять вашу память для чтения / записи
- Есть ли какая-либо информация, которую я пропустил / ошибся?
Прочитайте исходный код подобных драйверов, он уже содержит практически все решения для таких простых драйверов.