Advertisement
Astralix

Untitled

Jun 28th, 2017
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.28 KB | None | 0 0
  1. /**
  2.  * @file   mike.c
  3.  * @author Ulrich Prinz
  4.  * @date   28 June 2017
  5.  * @brief  A kernel module for reading the matrix keyboard of the DV4home microphone.
  6.  * sysfs /sys/class/gpio/gpio115 and gpio49. Therefore, this test LKM circuit assumes that an LED
  7.  * is attached to GPIO 49 which is on P9_23 and the button is attached to GPIO 115 on P9_27. There
  8.  * is no requirement for a custom overlay, as the pins are in their default mux mode states.
  9.  * @see http://www.derekmolloy.ie/
  10. */
  11.  
  12. #include <linux/init.h>
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/gpio.h>                 // Required for the GPIO functions
  16. #include <linux/interrupt.h>            // Required for the IRQ code
  17. #include <linux/kthread.h>
  18. #include <linux/delay.h>
  19.  
  20. MODULE_LICENSE("GPL");
  21. MODULE_AUTHOR("Ulrich Prinz");
  22. MODULE_DESCRIPTION("Mike keyboard control driver");
  23. MODULE_VERSION("0.1");
  24.  
  25. static unsigned int gpioData = 124;     /* GPIO is hard coded to GPIO4_
  26. // static unsigned int irqNumber;           ///< Used to share the IRQ number within this file
  27.  
  28. /* Initial blink delay */
  29. // static int blink_delay = 100;
  30.  
  31. /* Task handle to identify thread */
  32. static struct task_struct *ts = NULL;
  33.  
  34. /// Function prototype for the custom IRQ handler function -- see below for the implementation
  35. static irq_handler_t  mike_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
  36.  
  37. static int mike_thread( void *data)
  38. {
  39.     printk(KERN_INFO "%s\n", __func__);
  40.  
  41.     gpio_direction_output(gpioData, 0);
  42.  
  43.     while (!kthread_should_stop()) {
  44.         /* Set as output low */
  45.         printk(KERN_INFO "X\n");
  46.         //gpio_direction_output(gpioData, 0);
  47.         mdelay(100);
  48.         // gpio_direction_input(gpioData);
  49.         // gpio_direction_output(gpioData, 1);
  50.         mdelay(100);
  51.     }
  52.  
  53.     return 0;
  54. }
  55.  
  56. /** @brief The LKM initialization function
  57.  *  The static keyword restricts the visibility of the function to within this C file. The __init
  58.  *  macro means that for a built-in driver (not a LKM) the function is only used at initialization
  59.  *  time and that it can be discarded and its memory freed up after that point. In this example this
  60.  *  function sets up the GPIOs and the IRQ
  61.  *  @return returns 0 if successful
  62.  */
  63. static int __init mike_init(void)
  64.  
  65. {
  66.     int result = 0;
  67.     printk(KERN_INFO "MIKE_TEST: Initializing the GPIO\n");
  68.     // Is the GPIO a valid GPIO number (e.g., the BBB has 4x32 but not all available)
  69.     if (!gpio_is_valid(gpioData)) {
  70.         printk(KERN_INFO "GPIO_TEST: invalid LED GPIO\n");
  71.         return -ENODEV;
  72.     }
  73.  
  74.     gpio_request(gpioData, "sysfs");// gpioLED is hardcoded to 49, request it
  75.     gpio_direction_output(gpioData, 0);// Set the gpio to be in output mode and on
  76. //  gpio_set_value(gpioData, ledOn);          // Not required as set by line above (here for reference)
  77.     gpio_export(gpioData, false);// Causes gpio49 to appear in /sys/class/gpio
  78.             // the bool argument prevents the direction from being changed
  79. //  gpio_direction_input(gpioData);        // Set the button GPIO to be an input
  80. //  gpio_set_debounce(gpioData, 20);      // Debounce the button with a delay of 200ms
  81.  
  82.     // Perform a quick test to see that the button is working as expected on LKM load
  83.     printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioData));
  84. #if 0
  85.     // GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
  86.     irqNumber = gpio_to_irq(gpioButton);
  87.     printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irqNumber);
  88.  
  89.     // This next call requests an interrupt line
  90.     result = request_irq(irqNumber,// The interrupt number requested
  91.             (irq_handler_t) ebbgpio_irq_handler,// The pointer to the handler function below
  92.             IRQF_TRIGGER_RISING,// Interrupt on rising edge (button press, not release)
  93.             "ebb_gpio_handler",// Used in /proc/interrupts to identify the owner
  94.             NULL);// The *dev_id for shared interrupt lines, NULL is okay
  95.  
  96.     printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);
  97. #endif
  98.  
  99.     ts = kthread_create(mike_thread, NULL, "mike_thread");
  100.  
  101.     if(ts) {
  102.         wake_up_process(ts);
  103.     }
  104.     else {
  105.         printk(KERN_ERR "Unable to create thread\n");
  106.     }
  107.     return result;
  108. }
  109.  
  110. /** @brief The LKM cleanup function
  111.  *  Similar to the initialization function, it is static. The __exit macro notifies that if this
  112.  *  code is used for a built-in driver (not a LKM) that this function is not required. Used to release the
  113.  *  GPIOs and display cleanup messages.
  114.  */
  115. static void __exit mike_exit(void)
  116. {
  117.     printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioData));
  118.     gpio_unexport(gpioData);                  // Unexport the LED GPIO
  119.  
  120. //  free_irq(irqNumber, NULL);               // Free the IRQ number, no *dev_id required in this case
  121.     gpio_unexport(gpioData);// Unexport the Button GPIO
  122.     gpio_free(gpioData);// Free the LED GPIO
  123.     printk(KERN_INFO "Mike says: Goodbye!\n");
  124. }
  125.  
  126. /** @brief The GPIO IRQ Handler function
  127.  *  This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt
  128.  *  handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete.
  129.  *  This function is static as it should not be invoked directly from outside of this file.
  130.  *  @param irq    the IRQ number that is associated with the GPIO -- useful for logging.
  131.  *  @param dev_id the *dev_id that is provided -- can be used to identify which device caused the interrupt
  132.  *  Not used in this example as NULL is passed.
  133.  *  @param regs   h/w specific register values -- only really ever used for debugging.
  134.  *  return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise.
  135.  */
  136. static irq_handler_t mike_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
  137. {
  138. #if 0
  139.     ledOn = !ledOn;                 // Invert the LED state on each button press
  140.     gpio_set_value(gpioLED, ledOn);// Set the physical LED accordingly
  141.     printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)\n", gpio_get_value(gpioButton));
  142.     numberPresses++;// Global counter, will be outputted when the module is unloaded
  143. #endif
  144.     return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly
  145. }
  146.  
  147. /// This next calls are  mandatory -- they identify the initialization function
  148. /// and the cleanup function (as above).
  149. module_init(mike_init);
  150. module_exit(mike_exit);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement