Что на самом деле делает request_mem_region() и когда это необходимо?

#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.