首页 > 解决方案 > 从 GPIO 输入驱动程序公开 /dev/uio* 文件

问题描述

我制作了一个自定义内核模块来处理 GPIO 上的上升沿触发中断。我想在 /dev 目录中创建一个“uio”文件。我必须做什么?我需要声明一些结构并填写吗?如果有人可以分享相关示例,那就太好了。

下面是触发中断的自定义 GPIO 驱动程序的代码片段。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>                 // Required for the GPIO functions
#include <linux/interrupt.h>            // Required for the IRQ code

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Khilav Soni");
MODULE_DESCRIPTION("A Switch test driver");

static unsigned int gpio_switch = 65;   ///< hard coding the button gpio for this example to P9_27 (GPIO65)
static unsigned int irq_number;          ///< Used to share the IRQ number within this file

/// Function prototype for the custom IRQ handler function -- see below for the implementation
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);

/** @brief The LKM initialization function
 *  The static keyword restricts the visibility of the function to within this C file. The __init
 *  macro means that for a built-in driver (not a LKM) the function is only used at initialization
 *  time and that it can be discarded and its memory freed up after that point. In this example this
 *  function sets up the GPIOs and the IRQ
 *  @return returns 0 if successful
 */
static int __init ebbgpio_init(void){
   int result = 0;
   printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n");
   gpio_request(gpio_switch, "sysfs");       // Set up the gpioButton
   gpio_direction_input(gpio_switch);        // Set the button GPIO to be an input
   gpio_set_debounce(gpio_switch, 100);      // Debounce the button with a delay of 200ms
   //gpio_export(gpio_switch, false);          // Causes gpio115 to appear in /sys/class/gpio
                                // the bool argument prevents the direction from being changed
   // Perform a quick test to see that the button is working as expected on LKM load
   printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpio_switch));

   // GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
   irq_number = gpio_to_irq(gpio_switch);
   printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irq_number);

   // This next call requests an interrupt line
   result = request_irq(irq_number,             // The interrupt number requested
                        (irq_handler_t) ebbgpio_irq_handler, // The pointer to the handler function below
                        IRQF_TRIGGER_RISING,   // Interrupt on rising edge (button press, not release)
                        "switch-event",    // Used in /proc/interrupts to identify the owner
                        NULL);                 // The *dev_id for shared interrupt lines, NULL is okay

   printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);
   return result;
}

/** @brief The LKM cleanup function
 *  Similar to the initialization function, it is static. The __exit macro notifies that if this
 *  code is used for a built-in driver (not a LKM) that this function is not required. Used to release the
 *  GPIOs and display cleanup messages.
 */
static void __exit ebbgpio_exit(void){
   free_irq(irq_number, NULL);               // Free the IRQ number, no *dev_id required in this case
   gpio_unexport(gpio_switch);               // Unexport the Button GPIO
   gpio_free(gpio_switch);                   // Free the Button GPIO
}

/** @brief The GPIO IRQ Handler function
 *  This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt
 *  handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete.
 *  This function is static as it should not be invoked directly from outside of this file.
 *  @param irq    the IRQ number that is associated with the GPIO -- useful for logging.
 *  @param dev_id the *dev_id that is provided -- can be used to identify which device caused the interrupt
 *  Not used in this example as NULL is passed.
 *  @param regs   h/w specific register values -- only really ever used for debugging.
 *  return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise.
 */
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs){
   static unsigned int numberPresses = 0;  ///< For information, store the number of button presses
   printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)\n", gpio_get_value(gpio_switch));
   printk(KERN_INFO "GPIO_TEST: The button was pressed %d times\n", numberPresses);
   numberPresses++;                         // Global counter, will be outputted when the module is unloaded
   return (irq_handler_t) IRQ_HANDLED;      // Announce that the IRQ has been handled correctly
}

/// This next calls are  mandatory -- they identify the initialization function
/// and the cleanup function (as above).
module_init(ebbgpio_init);
module_exit(ebbgpio_exit);

标签: clinuxlinux-kernellinux-device-drivertuio

解决方案


推荐阅读