#c #linux-kernel #linux-device-driver #embedded-linux
#c #linux-ядро #linux-device-driver #встроенный-linux
Вопрос:
Я изучаю написание встроенного драйвера Linux и решил запустить несколько GPIO, чтобы убедиться, что я правильно понимаю книгу (LDD3, глава 9.4.1).
Я могу управлять правильными выводами GPIO, как и предполагалось (делая их высокими и низкими, я проверял мультиметром); однако я протестировал 2 фрагмента кода, один с request_mem_region()
, а другой без. Я ожидаю, что тот, без которого не удастся, но оба работают просто отлично.
Код с request_mem_region
:
if( request_mem_region( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF,DEVICE_NAME ) == NULL )
{
printk( KERN_ALERT
"GPIO_140_141_conf_phys error:%s: unable to obtain I/O memory address 0xllXn",
DEVICE_NAME, PIN3_CONF_PHYS );
return -EBUSY;
}
pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
//-----------------------------------------------------------------
if( request_mem_region( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5,DEVICE_NAME ) == NULL )
{
printk( KERN_ALERT
"error:%s: unable to obtain I/O memory address 0xllXn",
DEVICE_NAME, GPIO_BANK5_PHYS );
return -EBUSY;
}
gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );
//some iowrite32() functions continue...
Код без request_mem_region()
:
pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );
//some iowrite32() functions continue...
Единственное отличие, которое я могу наблюдать в обоих случаях, — это результат выполнения a cat /proc/iomem
, тот, у request_mem_region()
которого отображается дополнительная строка 49056000-49056097 : GPIO3
.
Мой вопрос в том, зачем request_mem_region()
это нужно, поскольку я все еще могу взаимодействовать только с аппаратным адресом ioremap()
? Итак, когда нам действительно нужно использовать request_mem_region()
?
Спасибо за любые ответы!
Ответ №1:
request_mem_region
сообщает ядру, что ваш драйвер собирается использовать этот диапазон адресов ввода-вывода, что не позволит другим драйверам выполнять какие-либо перекрывающиеся вызовы в тот же регион request_mem_region
. Этот механизм не выполняет никакого сопоставления, это чистый механизм резервирования, который основан на том факте, что все драйверы устройств ядра должны быть хорошими, и они должны вызывать request_mem_region
, проверять возвращаемое значение и вести себя должным образом в случае ошибки.
Так что вполне логично, что ваш код работает без request_mem_region
, просто он не соответствует правилам кодирования ядра.
Однако ваш код не соответствует стилю кодирования ядра. И, кроме того, существует существующая инфраструктура для обработки GPIO с именем gpiolib, которую вы должны использовать вместо ручного переназначения ваших банковских регистров GPIO. На какой платформе вы работаете?
Комментарии:
1. Спасибо за ответ! Это проясняет ситуацию для меня, я использую beagleboard с Angstrom. Я опубликовал еще один вопрос в группе beagleboard, и мне тоже предложили его использовать
gpiolib
. Однако я попробовал#include <linux/gpio.h>
или#include <asm/gpio.h>
, но оба потерпели неудачу, что мне следует использовать вместо этого?2. Другой вопрос, когда я делаю a
make
для компиляции модуля ядра или драйвера, в каких каталогах он будет искать заголовки#include
? Например, одним из них будет <MY_KDIR>/include , таким образом#include <linux/module.h>
, и#include <linux/kernel.h>
будет искать в <MY_DIR>/include/linux/ ; и#include <asm/io.h>
будет искать в <MY_DIR>/include/asm/ .3. @Petazzoni Извините за публикацию этого 3-го комментария, я только что узнал, что могу уведомить человека, отвечающего на мои вопросы, и я не смог отредактировать предыдущие комментарии, поэтому я должен опубликовать это.
Ответ №2:
Использование request_mem_region()
и ioremap()
в драйверах устройств теперь устарело. Вместо этого вы должны использовать приведенные ниже «управляемые» функции, которые упрощают кодирование драйвера и обработку ошибок:
devm_ioremap()
devm_iounmap()
devm_ioremap_resource(), Takes care of both the request and remapping operations
Посмотрите на слайд 289 учебного курса компании bootlin.